首页 文章 精选 留言 我的

精选列表

搜索[云数据库 Redis®],共10034篇文章
优秀的个人博客,低调大师

One Web & MKey

假期去接人,路过图书馆,进去溜了一圈,翻了下近期的<<程序员>>,有两件事影响很深。 One Web 很早以前(移动梦网时代)就开始流行WAP,至时下,很多门户网站还有独立的WAP站,供手机用户访问。当然,这个WAP站经过"大幅缩减"的,很简单的文字信息。其实,现在很多手机早已支持HTML显示了,访问3W站完全没问题。不过,现在以GPRS,EDGE为主要途径下,直接访问3W站浏量费是一个很大的问题,不过页面大小及内容做适当调整仍然采用HTML设计供手机终端访问是可以的。这样至少保证网站设计开放上可以做到统一,不用去考虑WML等手机特有的东西。作者的意思是在3G时代还WAP,这样其实是不利于移动互联网的发展,我很赞同他的观点。感觉现在没多大必要做WAP,现在很多手机站其实就是XHTML,跟PC终端呈现不同的就是页面大小针对手机屏大小,内容做适当精简,以文字加少量图片展示。 MKey 北京数字天堂的移动中间件产品,没实际用过,看想起来挺爽的。很大的降底了开发门槛,只要熟悉HTML,JavaScrpt很能很快入手,封装了很多底层的功能,开发者只需要关注业务逻辑,不用理会手机终端的差异。主要集中在企业级的应用,B/S系统中。不知安全性如何,有空关注下。 本文转自chy710博客园博客,原文链接:http://www.cnblogs.com/chy710/archive/2009/10/10/1580309.html ,如需转载请自行联系原作者

优秀的个人博客,低调大师

Docker核心实现技术(命名空间&amp;控制组&amp;联合文件系统&amp;Linux网络虚拟化支持)

作为一种容器虚拟化技术,Docker深度应用了操作系统的多项底层支持技术。 早期版本的Docker是基于已经成熟的Linux Container(LXC)技术实现的。自Docker 0.9版本起,Docker逐渐从LXC转移到新的libcontainer(https://github.com/docker/libcontainer)上,并且积极推动开放容器规范runc,试图打造更通用的底层容器虚拟化库。 从操作系统功能上看,目前Docker底层依赖的核心技术主要包括Linux操作系统的命名空间(Namespace)、控制组(Control Group)、联合文件系统(Union File System)和Linux网络虚拟化支持。 基本架构 Docker目前采用了标准的C/S架构。客户端和服务端既可以运行在一个机器上,也可运行在不同机器上通过socket或者RESTful API来进行通信。 1.服务端 Docker Daemon一般在宿主主机后台运行,作为服务端接受来自客户的请求,并处理这些请求(创建、运行、分发容器)。 在设计上,Docker Daemon是一个模块化的架构,通过专门的Engine模块来分发管理各个来自客户端的任务。 Docker服务端默认监听本地的unix:///var/run/docker.sock套接字,只允许本地的root用户或docker用户组成员访问。可以通过-H选项来修改监听的方式。 例如,让服务端监听本地的TCP连接1234端口,如下所示: $ docker daemon -H 0.0.0.0:1234 此外,Docker还支持通过HTTPS认证方式来验证访问。 Debian/Ubuntu 14.04等使用upstart管理启动服务的系统中,Docker服务端的默认启动配置文件在/etc/default/docker。对于使用systemd管理启动服务的系统,配置文件在/etc/systemd/system/docker.service.d/docker.conf。 2.客户端 Docker客户端为用户提供一系列可执行命令,用户用这些命令与Docker Daemon交互。 用户使用的Docker可执行命令即为客户端程序。与Docker Daemon不同的是,客户端发送命令后,等待服务端返回,一旦收到返回后,客户端立刻执行结束并退出。用户执行新的命令,需要再次调用客户端命令。同样,客户端默认通过本地的unix:///var/run/docker.sock套接字向服务端发送命令。如果服务端没有监听在默认的地址,则需要客户端在执行命令的时候显式指定服务端地址。 例如,假定服务端监听在本地的TCP连接1234端口tcp://127.0.0.1:1234,只有通过-H参数指定了正确的地址信息才能连接到服务端,如下所示: $ docker version Client: Version: 1.12.0 API version: 1.24 Go version: go1.6.3 Git commit: 8eab29e Built: Thu Sep 28 22:00:36 2016 OS/Arch: linux/amd64 Cannot connect to the Docker daemon. Is the docker daemon running on this host? $ docker -H tcp://127.0.0.1:1234 version Client: Version: 1.12.0 API version: 1.24 Go version: go1.6.3 Git commit: 8eab29e Built: Thu Sep 28 22:00:36 2016 OS/Arch: linux/amd64 Server: Version: 1.12.0 API version: 1.24 Go version: go1.6.3 Git commit: 8eab29e Built: Thu Sep 28 22:00:36 2016 OS/Arch: linux/amd64 3.新的架构设计 C/S架构给Docker基本功能的实现带来了许多便利,但同时也引入了一些限制。 使用Docker时,必须要启动并保持Docker Daemon的正常运行,它既要管理容器的运行时,又要负责提供对外部API的响应。而一旦Docker Daemon服务不正常,则已经运行在Docker主机上的容器也往往无法继续使用。 Docker团队已经意识到了这个问题,在较新的版本(1.11.0+)中,开始将维护容器运行的任务放到一个单独的组件containerd中来管理,并且支持OCI的runc规范。原先的对客户端API的支持则仍然放在Docker Daemon,通过解耦,大大减少了对Docker Daemon的依赖。同时,新的架构提高了启动容器的速度,一项测试表明,可以达到每秒启动超过100个容器。 命名空间 命名空间(namespace)是Linux内核的一个强大特性,为容器虚拟化的实现带来极大便利。 利用这一特性,每个容器都可以拥有自己单独的命名空间,运行在其中的应用都像是在独立的操作系统环境中一样。命名空间机制保证了容器之间彼此互不影响。 在操作系统中,包括内核、文件系统、网络、PID、UID、IPC、内存、硬盘、CPU等资源,所有的资源都是应用进程直接共享的。要想实现虚拟化,除了要实现对内存、CPU、网络IO、硬盘IO、存储空间等的限制外,还要实现文件系统、网络、PID、UID、IPC等的相互隔离。前者相对容易实现一些,后者则需要宿主主机系统的深入支持。 随着Linux系统对于命名空间功能的逐步完善,现在已经可以实现这些需求,让进程在彼此隔离的命名空间中运行。虽然这些进程仍在共用同一个内核和某些运行时环境(runtime,例如一些系统命令和系统库),但是彼此是不可见的,并且认为自己是独占系统的。 1.进程命名空间 Linux通过命名空间管理进程号,对于同一进程(即同一个task_struct),在不同的命名空间中,看到的进程号不相同,每个进程命名空间有一套自己的进程号管理方法。进程命名空间是一个父子关系的结构,子空间中的进程对于父空间是可见的。新fork出的进程在父命名空间和子命名空间将分别有一个进程号来对应。 例如,查看Docker主进程的pid进程号是5989,如下所示: $ ps -ef |grep docker root 5989 5988 0 14:38 pts/6 00:00:00 docker -d 新建一个Ubuntu的“hello world”容器: $ docker run -d ubuntu:14.04 /bin/sh -c "whiletrue;doechohello world;sleep 1; done" ec559327572b5bf99d0f80b98ed3a3b62023844c7fdbea3f8caed4ffa5c62e86 查看新建容器进程的父进程,正是Docker主进程5989: $ ps -ef |grepwhile root 6126 5989 0 14:41 ? 00:00:00 /bin/sh -cwhiletrue;doechohello world; sleep 1; done 2.网络命名空间 如果有了pid命名空间,那么每个命名空间中的进程就可以相互隔离,但是网络端口还是共享本地系统的端口。 通过网络命名空间,可以实现网络隔离。网络命名空间为进程提供了一个完全独立的网络协议栈的视图,包括网络设备接口、IPv4和IPv6协议栈、IP路由表、防火墙规则、sockets等,这样每个容器的网络就能隔离开来。Docker采用虚拟网络设备(Virtual Network Device)的方式,将不同命名空间的网络设备连接到一起。默认情况下,容器中的虚拟网卡将同本地主机上的docker0网桥连接在一起。 使用brctl工具可以看到桥接到宿主主机docker0网桥上的虚拟网口: $ brctl show bridge name bridge id STP enabled interfaces docker0 8000.56847afe9799 no veth4148vethd166vethd533 3.IPC命名空间 容器中进程交互还是采用了Linux常见的进程间交互方法(Interprocess Communication,IPC),包括信号量、消息队列和共享内存等。PID Namespace和IPC Namespace可以组合起来一起使用,同一个IPC命名空间内的进程可以彼此可见,允许进行交互;不同空间的进程则无法交互。 4.挂载命名空间 类似于chroot,将一个进程放到一个特定的目录执行。挂载命名空间允许不同命名空间的进程看到的文件结构不同,这样每个命名空间中的进程所看到的文件目录彼此被隔离。 5.UTS命名空间 UTS(UNIX Time-sharing System)命名空间允许每个容器拥有独立的主机名和域名,从而可以虚拟出一个有独立主机名和网络空间的环境,就跟网络上一台独立的主机一样。默认情况下,Docker容器的主机名就是返回的容器ID: $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ec559327572b ubuntu:14.04 /bin/sh -c 'whiletr 18 minutes agoUp 18 minutes furious_goodall $ docker inspect -f {{".Config.Hostname"}} ec5 ec559327572b 6.用户命名空间 每个容器可以有不同的用户和组id,也就是说可以在容器内使用特定的内部用户执行程序,而非本地系统上存在的用户。 每个容器内部都可以有root帐号,但跟宿主主机不在一个命名空间。 通过使用隔离的用户命名空间可以提高安全性,避免容器内进程获取到额外的权限。 控制组 控制组(CGroups)是Linux内核的一个特性,主要用来对共享资源进行隔离、限制、审计等。只有能控制分配到容器的资源,才能避免多个容器同时运行时对宿主机系统的资源竞争。控制组可以提供对容器的内存、CPU、磁盘IO等资源进行限制和计费管理。控制组的设计目标是为不同的应用情况提供统一的接口,从控制单一进程(比如nice工具)到系统级虚拟化(包括OpenVZ、Linux-VServer、LXC等)。 具体来看,控制组提供: 资源限制(Resource limiting):可以将组设置为不超过设定的内存限制。比如:内存子系统可以为进程组设定一个内存使用上限,一旦进程组使用的内存达到限额再申请内存,就会出发Out of Memory警告。 优先级(Prioritization):通过优先级让一些组优先得到更多的CPU等资源。 资源审计(Accounting):用来统计系统实际上把多少资源用到适合的目的上,可以使用cpuacct子系统记录某个进程组使用的CPU时间。 隔离(isolation):为组隔离命名空间,这样一个组不会看到另一个组的进程、网络连接和文件系统。 控制(Control):挂起、恢复和重启动等操作。 安装Docker后,用户可以在/sys/fs/cgroup/memory/docker/目录下看到对Docker组应用的各种限制项,包括: $ cd /sys/fs/cgroup/memory/docker $ ls 用户可以通过修改这些文件值来控制组限制Docker应用资源。 例如,通过下面的命令可限制Docker组中所有进程使用的物理内存总量不超过100MB: $ sudo echo 104857600 >/sys/fs/cgroup/memory/docker/memory.limit_in_bytes 进入对应的容器文件夹,可以看到对应容器的一些状态: $ cd 42352bb6c1d1c5c411be8fa04e97842da87d14623495189c4d865dfc444d12ae/ $ ls $ cat memory.stat 在开发容器工具时,往往需要一些容器运行状态数据,这时就可以从这里得到更多的信息。 可以在创建或启动容器时为每个容器指定资源的限制,例如使用-c|--cpu-shares[=0]参数来调整容器使用CPU的权重;使用-m|--memory[=MEMORY]参数来调整容器使用内存的大小。 联合文件系统 联合文件系统(UnionFS)是一种轻量级的高性能分层文件系统,它支持将文件系统中的修改信息作为一次提交,并层层叠加,同时可以将不同目录挂载到同一个虚拟文件系统下,应用看到的是挂载的最终结果。 联合文件系统是实现Docker镜像的技术基础。Docker镜像可以通过分层来进行继承。例如,用户基于基础镜像(用来生成其他镜像的基础,往往没有父镜像)来制作各种不同的应用镜像。这些镜像共享同一个基础镜像层,提高了存储效率。此外,当用户改变了一个Docker镜像(比如升级程序到新的版本),则会创建一个新的层(layer)。因此,用户不用替换整个原镜像或者重新建立,只需要添加新层即可。用户分发镜像的时候,也只需要分发被改动的新层内容(增量部分)。这让Docker的镜像管理变得十分轻量级和快速。 1.Docker存储 Docker目前通过插件化方式支持多种文件系统后端。Debian/Ubuntu上成熟的AUFS(Another Union File System,或v2版本往后的Advanced Multilayered Unification File System),就是一种联合文件系统实现。AUFS支持为每一个成员目录(类似Git的分支)设定只读(readonly)、读写(readwrite)或写出(whiteout-able)权限,同时AUFS里有一个类似分层的概念,对只读权限的分支可以在逻辑上进行增量地修改(不影响只读部分的)。 Docker镜像自身就是由多个文件层组成,每一层有唯一的编号(层ID)。 可以通过docker history查看一个镜像由哪些层组成。例如查看ubuntu:14.04镜像由4层组成,每层执行了不同的命令: $ docker history ubuntu:14.04 IMAGE CREATED CREATED BY SIZE COMMENT 2a274e3405ec 13 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0 B df697c8b1bf4 13 months ago /bin/sh -c sed -i 's/^#\s*\(deb.*universe\)$/ 1.895 kB 371166fb96e0 13 months ago /bin/sh -c echo '#!/bin/sh' > /usr/sbin/polic 194.5 kB 69191ca023af 13 months ago /bin/sh -c #(nop) ADD file:c8f078961a543cdefa 188.1 MB 对于Docker镜像来说,这些层的内容都是不可修改的、只读的。而当Docker利用镜像启动一个容器时,将在镜像文件系统的最顶端再挂载一个新的可读写的层给容器。容器中的内容更新将会发生在可读写层。当所操作对象位于较深的某层时,需要先复制到最上层的可读写层。当数据对象较大时,往往意味着IO性能较差。因此,一般推荐将容器修改的数据通过volume方式挂载,而不是直接修改镜像内数据。此外,对于频繁启停Docker容器的场景下,文件系统的IO性能也将十分关键。具体看,Docker所有的存储都在Docker目录下,以Ubuntu系统为例,默认路径是/var/lib/docker。 在这个目录下面,存储由Docker镜像和容器运行相关的文件和目录,可能包括aufs、containers、graph、image、init、linkgraph.db、network、repositories-aufs、swarm、tmp、trust、volumes等。 最关键的就是aufs目录,这是aufs文件系统所在,保存Docker镜像相关数据和信息。该目录包括layers、diff和mnt三个子目录。1.9版本和之前的版本中,命名跟镜像层的ID是匹配的,而自1.10开始,层数据相关的文件和目录名与层ID不再匹配。 layers子目录包含层属性文件,用来保存各个镜像层的元数据:某镜像的某层下面包括哪些层。 例如:某镜像由5层组成,则文件内容应该如下: # cat aufs/layers/78f4601eee00b1f770b1aecf5b6433635b99caa5c11b8858dd6c8cec03b4584f-init d2a0ecffe6fa4ef3de9646a75cc629bbd9da7eead7f767cb810f9808d6b3ecb6 29460ac934423a55802fcad24856827050697b4a9f33550bd93c82762fb6db8f b670fb0c7ecd3d2c401fbfd1fa4d7a872fbada0a4b8c2516d0be18911c6b25d6 83e4dde6b9cfddf46b75a07ec8d65ad87a748b98cf27de7d5b3298c1f3455ae4 diff子目录包含层内容子目录,用来保存所有镜像层的内容数据。 例如:# ls aufs/diff/78f4601eee00b1f770b1aecf5b6433635b99caa5c11b8858dd6c8cec03b4584f-init/ dev etc mnt子目录下面的子目录是各个容器最终的挂载点,所有相关的AUFS层在这里挂载到一起,形成最终效果。一个运行中容器的根文件系统就挂载在这下面的子目录上。同样,1.10版本之前的Docker中,子目录名和容器ID是一致的。其中,还包括容器的元数据、配置文件和运行日志等。 2.多种文件系统比较 Docker目前支持的联合文件系统种类包括AUFS、OverlayFS、btrfs、vfs、zfs和Device Mapper等。 各种文件系统目前的支持情况如下: AUFS:最早支持的文件系统,对Debian/Ubuntu支持好,虽然没有合并到Linux内核中,但成熟度很高; OverlayFS:类似于AUFS,性能更好一些,已经合并到内核,未来会取代AUFS,但成熟度有待提高; Device Mapper:Redhat公司和Docker团队一起开发用于支持RHEL的文件系统,内核支持,性能略慢,成熟度高; btrfs:参考zfs等特性设计的文件系统,由Linux社区开发,试图未来取代Device Mapper,成熟度有待提高; vfs:基于普通文件系统(ext、nfs等)的中间层抽象,性能差,比较占用空间,成熟度也一般。 zfs:最初设计为Solaris 10上的写时文件系统,拥有不少好的特性,但对Linux支持还不够成熟。 总结一下,AUFS和Device Mapper的应用最为广泛,支持也相对成熟,推荐生产环境考虑。长期来看,OverlayFS将可能具有更好的特性。 Linux网络虚拟化 Docker的本地网络实现其实就是利用了Linux上的网络命名空间和虚拟网络设备(特别是veth pair)。 1.基本原理 直观上看,要实现网络通信,机器需要至少一个网络接口(物理接口或虚拟接口)与外界相通,并可以收发数据包;此外,如果不同子网之间要进行通信,需要额外的路由机制。 Docker中的网络接口默认都是虚拟的接口。虚拟接口的最大优势就是转发效率极高。这是因为Linux通过在内核中进行数据复制来实现虚拟接口之间的数据转发,即发送接口的发送缓存中的数据包将被直接复制到接收接口的接收缓存中,而无需通过外部物理网络设备进行交换。对于本地系统和容器内系统来看,虚拟接口跟一个正常的以太网卡相比并无区别,只是它速度要快得多。 Docker容器网络就很好地利用了Linux虚拟网络技术,在本地主机和容器内分别创建一个虚拟接口,并让它们彼此连通(这样的一对接口叫做veth pair)。 一般情况下,Docker创建一个容器的时候,会具体执行如下操作: 创建一对虚拟接口,分别放到本地主机和新容器的命名空间中; 本地主机一端的虚拟接口连接到默认的docker0网桥或指定网桥上,并具有一个以veth开头的唯一名字,如veth1234; 容器一端的虚拟接口将放到新创建的容器中,并修改名字作为eth0。这个接口只在容器的命名空间可见; 从网桥可用地址段中获取一个空闲地址分配给容器的eth0(例如172.17.0.2/16),并配置默认路由网关为docker0网卡的内部接口docker0的IP地址(例如172.17.42.1/16)。 完成这些之后,容器就可以使用它所能看到的eth0虚拟网卡来连接其他容器和访问外部网络。用户也可以通过docker network命令来手动管理网络。 在使用docker run命令启动容器的时候,可以通过--net参数来指定容器的网络配置。 有5个可选值bridge、none、container、host和用户定义的网络: --net=bridge:默认值,在Docker网桥docker0上为容器创建新的网络栈。 --net=none:让Docker将新容器放到隔离的网络栈中,但是不进行网络配置。之后,用户可以自行进行配置。 --net=container:NAME_or_ID:让Docker将新建容器的进程放到一个已存在容器的网络栈中,新容器进程有自己的文件系统、进程列表和资源限制,但会和已存在的容器共享IP地址和端口等网络资源,两者进程可以直接通过lo环回接口通信。 --net=host:告诉Docker不要将容器网络放到隔离的命名空间中,即不要容器化容器内的网络。此时容器使用本地主机的网络,它拥有完全的本地主机接口访问权限。容器进程可以跟主机其他root进程一样打开低范围的端口,可以访问本地网络服务,比如D-bus,还可以让容器做一些影响整个主机系统的事情,比如重启主机。因此使用这个选项的时候要非常小心。如果进一步的使用--privileged=true参数,容器甚至会被允许直接配置主机的网络栈。 --net=user_defined_network:用户自行用network相关命令创建一个网络,通过这种方式将容器连接到指定的已创建网络上去。 3.手动配置网络 用户使用--net=none后,Docker将不对容器网络进行配置。 下面,将手动完成配置网络的整个过程。 首先,启动一个/bin/bash容器,指定--net=none参数: $ docker run -i -t --rm --net=none base /bin/bash root@63f36fc01b5f:/# 在本地主机查找容器的进程id,并为它创建网络命名空间: $ docker inspect -f '{{.State.Pid}}' 63f36fc01b5f 2778 $ pid=2778 $ sudomkdir-p /var/run/netns $ sudo ln -s /proc/$pid/ns/net /var/run/netns/$pid 检查桥接网卡的IP和子网掩码信息: $ ip addr show docker0 21: docker0: ... inet 172.17.42.1/16 scopeglobaldocker0 ... 创建一对“veth pair”接口A和B,绑定A接口到网桥docker0,并启用它: $ sudo ip link add A type veth peer name B $ sudo brctl addif docker0 A $ sudo ip link set A up 将B接口放到容器的网络命名空间,命名为eth0,启动它并配置一个可用IP(桥接网段)和默认网关: $ sudo ip link set B netns$pid $ sudo ip netnsexec$pidip link set dev B name eth0 $ sudo ip netnsexec$pidip link set eth0 up $ sudo ip netnsexec$pidip addr add 172.17.42.99/16 dev eth0 $ sudo ip netnsexec$pidip route adddefaultvia 172.17.42.1 以上,就是Docker配置网络的具体过程。 当容器终止后,Docker会清空容器,容器内的网络接口会随网络命名空间一起被清除,A接口也会自动从docker0卸载并清除。 此外,在删除/var/run/netns/下的内容之前,用户可以使用ip netns exec命令在指定网络命名空间中进行配置,从而更新容器内的网络配置。

优秀的个人博客,低调大师

深入了解高可用注册中心-&amp;amp;gt;Spring Cloud Eureka

在微服务架构这样的分布式环境中,我们需要充分考虑发生故障的情况, 所以在生产 环境中必须对各个组件进行高可用部署, 对于微服务如此, 对于服务注册中心也一样。 但 是到本节为止,我们一直都在使用单节点的服务注册中心,这在生产环境中显然并不合适, 我们需要构建高可用的服务注册中心以增强系统的可用性。 Eureka Server的设计一开始就考虑了高可用问题, 在Eureka的服务治理设计中, 所有 节点即是服务提供方, 也是服务消费方, 服务注册中心也不例外。 是否还记得在单节点的 配置中,我们设置过下面这两个参数, 让服务注册中心不注册自己: eureka.client.register-with-eureka=false eureka.client.fetch-registry=false Eureka Server的高可用实际上就是将自己作为服务向其他服务注册中心注册自己,这 样就可以形成一组互相注册的服务注册中心, 以实现服务清单的互相同步, 达到高可用的 效果。 下面我们就来尝试搭建高可用服务注册中心的集群。 目录结构 在etc/hosts文件中添加对peerl和peer2的转换, 让上面配置的host形式的 serviceUrl能在本地正确访间到; Windows系统路径为C:WindowsSystem32 driversetchosts。 1 2 127.0.0.1 peer1 127.0.0.1 peer2 启动: java -jar Eureka-0.0.1-SNAPSHOT.jar --spring.profiles.active=peer1 java -jar Eureka-0.0.1-SNAPSHOT.jar --spring.profiles.active=peer2 peer1图 peer2图 此时访问peer1的注册中心http://localhost:1111/, 如下图所示, 我们可以到看, registered-replicas中已经有peer2节点的eureka-server了。 同样的, 我们访 问peer2的注册中心http://localhost: 2222/ , 也能到看registered-replicas 中已经有peer1节点,并且这些节点在可用分片(available-replicase)之中。 在设置了多节点的服务注册中心之后, 服务提供方还需要做一些简单的配置才能将 服务注册到Eureka Server 集群中。 我们以下面的项目为例, 修改 application.properties 配置文件, 如下所示: 修改pom.xml 上面的配置主要对eureka.client.serviceUrl.defaultZone属性做了改动, 将注册中心指向了之前我们搭建的peerl与peer2(类似于dubbo服务)。 访问地址: http://localhost:1111/ http://localhost:2222/ 可以观察到hello-service 服务同时被注册到了peerl和peer2上。若此时断开peer!, 由于compute-service同时也向peer2注册, 因此在peer2上的 其他服务依然能访问到hello-service, 从而实现了服务注册中心的高可用。 想深入了解Spring Cloud,想提升职业技能么,这里有在大型企业工作十余年的架构师分享经验,Java工程化管理、高性能、分布式、高可用架构、zookeeper、Spring cloud,MyBatis,Netty源码分析和大数据等多个知识点高级进阶干货的直播讲解以及在线答疑,如果你想拿高薪的,想学习的,想就业前景好的,想跟别人竞争能取得优势的,想进阿里面试但担心面试不过的,你都可以来,QQ群号为:468947140

优秀的个人博客,低调大师

Template parsing error: template: :1:2: executing at &amp;lt;Volumes&amp;gt;: ...

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34173549/article/details/80400454 报错: [root@ops-ip-statistic ~]# docker inspect -f {{.Volumes}} volume-test1 Template parsing error: template: :1:2: executing "" at <.Volumes>: map has no entry for key "Volumes" 1 2 3 解决: 1,使用 “.Config.Volumes” 替换 “.Volumes” [root@ops-ip-statistic ~]# docker inspect -f {{.Config.Volumes}} volume-test1 map[/data:{}] 1 2 显示为空,此法 在此不可行 2,直接看容器的所有信息 再grep [root@ops-ip-statistic _data]# docker inspect volume-test1 | grep Mounts -A 10 "Mounts": [ { "Name": "0a3d70900bd0fa46c797f7aa7ff5176b7f6a5a798b6a282cd6c532facfd24925", "Source": "/var/lib/docker/volumes/0a3d70900bd0fa46c797f7aa7ff5176b7f6a5a798b6a282cd6c532facfd24925/_data", "Destination": "/data", "Driver": "local", "Mode": "", "RW": true, "Propagation": "" } ], 1 2 3 4 5 6 7 8 9 10 11 12 找到对应的目录是: /var/lib/docker/volumes/0a3d70900bd0fa46c797f7aa7ff5176b7f6a5a798b6a282cd6c532facfd24925/_data 1 进入容器中创建一个文件: [root@nginx data]# echo 123 >a [root@nginx data]# cat a 123 1 2 3 在宿主机的对应的目录中查看: [root@ops-ip-statistic _data]# cd /var/lib/docker/volumes/0a3d70900bd0fa46c797f7aa7ff5176b7f6a5a798b6a282cd6c532facfd24925/_data [root@ops-ip-statistic _data]# cat a 123 1 2 3 可行!

优秀的个人博客,低调大师

Android Studio中解决Gradle DSL method not found: &amp;#39;android()&amp;#39;

近期导入as的项目出了这种问题 这个问题困扰了我非常长时间,好吧,搜了半天全都是runProguard的。最后在stackoverflow上搜到解决的方法了:http://stackoverflow.com/questions/27735646/android-studio-gradle-dsl-method-not-found-android-error17-0 解决方法: 删掉最外层的build.gradle中的 android { compileSdkVersion 19 buildToolsVersion '21.1.1' } 然后又一次刷新就ok了 本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/5275790.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

《现代教育技术》Win8版发布 &amp;&amp; 项目总结

Win8处女作《现代教育技术》发布快一周了,小小总结下。 项目总共三个平台,iPad、Web、Win8,独立完成了iPad版及Win8版,也算完整了,=.=。 iPad版: 是一个native+html的项目,主要解决的技术点是WebView的Page Scroll的效果,以及OC与JS的交互,如OC怎么监听JS事件。 具体可参考我的博文:iOS:UIWebView scrollView 的分页滑动问题 iOS: 在Object-C中监听javascript事件( Javascript communicating back with Objective-C code) Win8版: Win8的开发我们使用的开发方式是HTML5+CSS3+WInjs。html+css主要作用于视图层,winjs实现于逻辑层。所以要找到类MVC模式还是有的。项目之后也对前端的一些技术有了解到了。 毕竟是刚出来的平台,在项目的细节处会体验到MS在一些api细节做得还不够完善,一些实现有时得绕着圈才能完成。 项目一个要解决的问题是适配多分辨率。现在win8在开发中适配问题介于iOS和Android之间,它没有iOS不必为多分辨率适配担忧,但也没有Android的种类繁多。但是解决的话还是能从Android中借鉴一些经验过来的,比如其中用得最多的就是利用百分比的方法去实现。 1、css中所有用到大小、长宽的都只能使用百分比去设定; 2、面对listview的时候,有时css的 设定item size不能满足效果,就需要在js动态做调整:e.g. 获取屏幕可用宽高: 在listview template中设定: 剩下的更多的是界面排布的问题,这个得用html css去做,前端的知识会有帮助。 项目发现用这种方式开发的话,没有webview的控件,webview在C#,xaml的开发方式中才有。这个很不方便,虽然html有iframe替代,但是我们很难去同IFrame的内容交互,这会导致直接不能同web端交互,不够灵活。 但是MS对开发Win8 modern App 提供2种方案,无疑是想吸引更多开发者,C# xaml的方案比较适用于Android或 ios开发者转移,winjs的方案更使用于web 开发者转移。如果你会web开发,上手win8开发其实会是十分容易的事。 最后贴下2个平台产品的图: ipad:下载地址:https://itunes.apple.com/cn/app/xian-dai-jiao-yu-ji-shu/id595581360?mt=8 Win8: 下载地址:http://apps.microsoft.com/windows/zh-CN/app/6731b692-b272-4784-9f91-a78b457685eb 本文转自老Zhan博客园博客,原文链接:http://www.cnblogs.com/mybkn/archive/2013/05/13/3074961.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

Manifest.xml 入门基础 (五)&amp;lt;Activity&amp;gt;标签

<activity android:allowTaskReparenting=["true" | "false"] android:alwaysRetainTaskState=["true" | "false"] android:clearTaskOnLaunch=["true" | "false"] android:configChanges=["mcc", "mnc", "locale", "touchscreen", "keyboard", "keyboardHidden", "navigation", "orientation", "screenLayout", "fontScale", "uiMode"] android:enabled=["true" | "false"] android:excludeFromRecents=["true" | "false"] android:exported=["true" | "false"] android:finishOnTaskLaunch=["true" | "false"] android:icon="drawable resource" android:label="string resource" android:launchMode=["multiple" | "singleTop" | "singleTask" | "singleInstance"] android:multiprocess=["true" | "false"] android:name="string" android:noHistory=["true" | "false"] android:permission="string" android:process="string" android:screenOrientation=["unspecified" | "user" | "behind" | "landscape" | "portrait" | "sensor" | "nosensor"] android:stateNotNeeded=["true" | "false"] android:taskAffinity="string" android:theme="resource or theme" android:windowSoftInputMode=["stateUnspecified", "stateUnchanged", "stateHidden", "stateAlwaysHidden", "stateVisible", "stateAlwaysVisible", "adjustUnspecified", "adjustResize", "adjustPan"] > </activity> A、android:alwaysRetainTaskState 是否保留状态不变, 比如切换回home, 再从新打开,activity处于最后的状态。比如一个浏览器拥有很多状态(当打开了多个TAB的时候),用户并不希望丢失这些状态时,此时可将此属性设置为true B、android:clearTaskOnLaunch 比如 P 是 activity, Q 是被P 触发的 activity, 然后返回Home, 重新启动 P,是否显示 Q C、android:configChanges 当配置list发生修改时, 是否调用 onConfigurationChanged() 方法 比如 “locale|navigation|orientation”. 这个我用过,主要用来看手机方向改变的. android手机在旋转后,layout会重新布局, 如何做到呢?正常情况下. 如果手机旋转了.当前Activity后杀掉,然后根据方向重新加载这个Activity. 就会从onCreate开始重新加载.如果你设置了 这个选项, 当手机旋转后,当前Activity之后调用onConfigurationChanged() 方法. 而不跑onCreate方法等. D、android:excludeFromRecents 是否可被显示在最近打开的activity列表里,默认是false E、android:finishOnTaskLaunch 当用户重新启动这个任务的时候,是否关闭已打开的activity,默认是false如果这个属性和allowTaskReparenting都是true,这个属性就是王牌。Activity的亲和力将被忽略。该Activity已经被摧毁并非re-parented F、android:launchMode(Activity加载模式) 在多Activity开发中,有可能是自己应用之间的Activity跳转,或者夹带其他应用的可复用Activity。可能会希望跳转到原来某个Activity实例,而不是产生大量重复的Activity。这需要为Activity配置特定的加载模式,而不是使用默认的加载模式 Activity有四种加载模式: standard、singleTop、singleTask、singleInstance(其中前两个是一组、后两个是一组),默认为standard standard:就是intent将发送给新的实例,所以每次跳转都会生成新的activity。 singleTop:也是发送新的实例,但不同standard的一点是,在请求的Activity正好位于栈顶时(配置成singleTop的Activity),不会构造新的实例 singleTask:和后面的singleInstance都只创建一个实例,当intent到来,需要创建设置为singleTask的Activity的时候,系统会检查栈里面是否已经有该Activity的实例。如果有直接将intent发送给它。 singleInstance:首先说明一下task这个概念,Task可以认为是一个栈,可放入多个Activity。比如启动一个应用,那么Android就创建了一个Task,然后启动这个应用的入口Activity,那在它的界面上调用其他的Activity也只是在这个task里面。那如果在多个task中共享一个Activity的话怎么办呢。举个例来说,如果开启一个导游服务类的应用程序,里面有个Activity是开启GOOGLE地图的,当按下home键退回到主菜单又启动GOOGLE地图的应用时,显示的就是刚才的地图,实际上是同一个Activity,实际上这就引入了singleInstance。singleInstance模式就是将该Activity单独放入一个栈中,这样这个栈中只有这一个Activity,不同应用的intent都由这个Activity接收和展示,这样就做到了共享。当然前提是这些应用都没有被销毁,所以刚才是按下的HOME键,如果按下了返回键,则无效。 G、android:multiprocess 是否允许多进程,默认是false 在实际开发中,CP有以下两种用法: 1)和应用在一个APK包里 这种情况下和应用在同一进程中。process name和uid都一样。 2)单独在一个APK包里。 这种情况下,如果在AndroidManifest.xml文件里声明了和某个进程同属一个进程,如: package="com.android.providers.telephony" android:sharedUserId="android.uid.phone"> android:allowClearUserData="false" android:label="Dialer Storage" android:icon="@drawable/ic_launcher_phone"> android:authorities="telephony" android:multiprocess="true" 这个里面通过android:sharedUserId=”android.uid.phone”和android:process=”com.android.phone”声明了该CP是和phone进程同属一个进程,拥有同样的process name和uid. 如果没有上述声明,那么该CP是在独立的进程中,拥有属于自己的process name和uid. 以上两种用法可以总结为: 1)CP和某个进程同属一个进程 这种情况下,当该进程启动时,会搜索属于该进程的所有CP,并加载。 2)CP属于独立的一个进程。 这种情况下,只有需要用到该CP时,才会去加载。 那么,当一个进程想要操作一个CP时,先需要获取该CP的对象,系统是如何处理呢: 1)如果该CP属于当前主叫进程,因为在进程启动时就已经加载过了,所以系统会直接返回该CP的对象。 2)如果该CP不属于当前主叫进程,那么系统会进行相关处理(由ActivityManagerService进行,以下简称为AMS): 所有已加载的CP信息都已保存在AMS中。当需要获取某个CP的对象时,AMS会先判断该CP是否已被加载 —-如果已被加载,该CP和当前主叫进程不属一个进程,但是该CP设置了multiprocess的属性(如上例中的android:multiprocess=”true”),并且该CP属于系统级CP,那么就在当前主叫进程内部新生成该CP的对象。否则就需要通过IPC机制进行调用。 —-如果还未被加载,该CP和当前主叫进程不属一个进程,但是该CP设置了multiprocess的属性(如上例中的android:multiprocess=”true”),并且该CP属于系统级CP,那么就在当前主叫进程内部新生成该CP的对象。否则就需要先创建该CP所在的进程,然后再通过IPC机制进行调用。 H、android:noHistory 当用户从Activity上离开并且它在屏幕上不再可见时,Activity是否从Activity stack中清除并结束。默认是false。Activity不会留下历史痕迹 I、android:screenOrientation activity显示的模式 默认为unspecified:由系统自动判断显示方向 landscape横屏模式,宽度比高度大 portrait竖屏模式, 高度比宽度大 user模式,用户当前首选的方向 behind模式:和该Activity下面的那个Activity的方向一致(在Activity堆栈中的) sensor模式:有物理的感应器来决定。如果用户旋转设备这屏幕会横竖屏切换 nosensor模式:忽略物理感应器,这样就不会随着用户旋转设备而更改了 J、android:stateNotNeeded activity被销毁或者成功重启时是否保存状态 K、android:windowSoftInputMode activity主窗口与软键盘的交互模式,可以用来避免输入法面板遮挡问题,Android1.5后的一个新特性。 这个属性能影响两件事情: 【A】当有焦点产生时,软键盘是隐藏还是显示 【B】是否减少活动主窗口大小以便腾出空间放软键盘 各值的含义: 【A】stateUnspecified:软键盘的状态并没有指定,系统将选择一个合适的状态或依赖于主题的设置 【B】stateUnchanged:当这个activity出现时,软键盘将一直保持在上一个activity里的状态,无论是隐藏还是显示 【C】stateHidden:用户选择activity时,软键盘总是被隐藏 【D】stateAlwaysHidden:当该Activity主窗口获取焦点时,软键盘也总是被隐藏的 【E】stateVisible:软键盘通常是可见的 【F】stateAlwaysVisible:用户选择activity时,软键盘总是显示的状态 【G】adjustUnspecified:默认设置,通常由系统自行决定是隐藏还是显示 【H】adjustResize:该Activity总是调整屏幕的大小以便留出软键盘的空间 【I】adjustPan:当前窗口的内容将自动移动以便当前焦点从不被键盘覆盖和用户能总是看到输入内容的部分。 一般情况下,在新建一个activity后,为了使intent可以调用此活动,我们要在androidManifest.xml文件中添加一个<activity>标签,<activity>标签的一般格式如下: <activity android:name="my.test.intents.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> 其中,”android:name”是活动对应的类名称,”android:label”是活动标题栏显示的内容,<intent-filter>是意图筛选器,<action>是动作名称,是指intent要执行的动作,<category>是类别名称,一般情况下,每个<intent-filter> 中都要显示指定一个默认的类别名称,即<category android:name=”android.intent.category.DEFAULT” />,但是上面的代码中没有指定默认类别名称,这是一个例外情况,因为其<intent-filter> 中的<action>是”android.intent.action.MAIN”,意思是这项活动是应用程序的入口点,这种情况下可以不加默认类别名称。 当然,除<action>和<category>以外,<intent-filter>中还有很多其他元素,在这里不详述。 上面的代码是androidManifest.xml中定义程序入口活动的例子,下面我们写一个自定义的例子: <activity android:name=".MyBrowserActivity" android:label="My Activity" > <intent-filter> <action android:name="my.test.MyBrowser"/> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="http"/> </intent-filter> </activity> 在这个<activity>标签中,我们指定活动的类为MyBrowserActivity.class,活动的标题显示为”My Activity”,<action android:name=”my.test.MyBrowser”/>意味着其他活动可以通过my.test.MyBrowser动作来调用这个活动,”my.test.MyBrowser”只是我们定义的一个动作的名称,写成包的形式是因为这样使我们更容易理解它的含义,如果我们把”my.test.MyBrowser”改成任意的内容如:”somethingelse”,同样,我们可以通过这个新的动作名称,来调用这个活动。<data> 元素指定了活动期望的数据类型,在这里,它期望的数据要以http://前缀开头。

优秀的个人博客,低调大师

Manifest.xml 入门基础 (四) &amp;lt;application&amp;gt;标签

Manifest.xml 入门基础 (四) <application>标签 一个AndroidManifest.xml中必须含有一个Application标签,这个标签声明了每一个应用程序的组件及其属性(如icon,label,permission等) <application android:allowClearUserData=["true" | "false"] android:allowTaskReparenting=["true" | "false"] android:backupAgent="string" android:debuggable=["true" | "false"] android:description="string resource" android:enabled=["true" | "false"] android:hasCode=["true" | "false"] android:icon="drawable resource" android:killAfterRestore=["true" | "false"] android:label="string resource" android:manageSpaceActivity="string" android:name="string" android:permission="string" android:persistent=["true" | "false"] android:process="string" android:restoreAnyVersion=["true" | "false"] android:taskAffinity="string" android:theme="resource or theme" > </application> 1.android:allowClearUserData(‘true’ or ‘false’) 用户是否能选择自行清除数据,默认为true,程序管理器包含一个选择允许用户清除数据。当为true时,用户可自己清理用户数据,反之亦然 2.android:allowTaskReparenting(‘true’ or ‘false’) 是否允许activity更换从属的任务,比如从短信息任务切换到浏览器任务 3.android:backupAgent 这也是Android2.2中的一个新特性,设置该APP的备份,属性值应该是一个完整的类名,如com.project.TestCase,此属性并没有默认值,并且类名必须得指定(就是个备份工具,将数据备份到云端的操作) 4.android:debuggable 这个从字面上就可以看出是什么作用的,当设置为true时,表明该APP在手机上可以被调试。默认为false,在false的情况下调试该APP,就会报以下错误: Device XXX requires that applications explicitely declare themselves as debuggable in their manifest. Application XXX does not have the attribute ‘debuggable’ set to TRUE in its manifest and cannot be debugged. 5.android:description/android:label 此两个属性都是为许可提供的,均为字符串资源,当用户去看许可列表(android:label)或者某个许可的详细信息(android:description)时,这些字符串资源就可以显示给用户。label应当尽量简短,之需要告知用户该许可是在保护什么功能就行。而description可以用于具体描述获取该许可的程序可以做哪些事情,实际上让用户可以知道如果他们同意程序获取该权限的话,该程序可以做什么。我们通常用两句话来描述许可,第一句描述该许可,第二句警告用户如果批准该权限会可能有什么不好的事情发生 6.android:enabled Android系统是否能够实例化该应用程序的组件,如果为true,每个组件的enabled属性决定那个组件是否可以被 enabled。如果为false,它覆盖组件指定的值;所有组件都是disabled。 7.android:hasCode(‘true’ or ‘false’) 表示此APP是否包含任何的代码,默认为true,若为false,则系统在运行组件时,不会去尝试加载任何的APP代码 一个应用程序自身不会含有任何的代码,除非内置组件类,比如Activity类,此类使用了AliasActivity类,当然这是个罕见的现象 (在Android2.3可以用标准C来开发应用程序,可在androidManifest.xml中将此属性设置为false,因为这个APP本身已经不含有任何的JAVA代码了) 8.android:icon 这个很简单,就是声明整个APP的图标,图片一般都放在drawable文件夹下 9.android:killAfterRestore 是否复位需要重启 10.android:manageSpaceActivity 让应用手动管理应用的数据目录 11.android:name 为应用程序所实现的Application子类的全名。当应用程序进程开始时,该类在所有应用程序组件之前被实例化。 若该类(比方androidMain类)是在声明的package下,则可以直接声明android:name=”androidMain”,但此类是在package下面的子包的话,就必须声明为全路径或android:name=”package名称.子包名成.androidMain” 12.android:permission 设置许可名,这个属性若在上定义的话,是一个给应用程序的所有组件设置许可的便捷方式,当然它是被各组件设置的许可名所覆盖的 13.android:presistent 该应用程序是否应该在任何时候都保持运行状态,默认为false。这个属性指定systemUI会在启动后一直运行下去。如果这个标记为false,则这个应用程序会被系统在资源匮乏的时候回收。大部分应用程序都是不会被设置为true的,而systemUI是一个系统程序,所以被设置为true。 14.android:process 应用程序运行的进程名,它的默认值为元素里设置的包名,当然每个组件都可以通过设置该属性来覆盖默认值。如果你想两个应用程序共用一个进程的话,你可以设置他们的android:process相同,但前提条件是他们共享一个用户ID及被赋予了相同证书的时候 15.android:restoreAnyVersion 同样也是android2.2的一个新特性,用来表明应用是否准备尝试恢复所有的备份,甚至该备份是比当前设备上更要新的版本,默认是false 16.android:taskAffinity 拥有相同的affinity的Activity理论上属于相同的Task,应用程序默认的affinity的名字是元素中设定的package名 17.android:theme 是一个资源的风格,它定义了一个默认的主题风格给所有的activity,当然也可以在自己的theme里面去设置它,有点类似style。

优秀的个人博客,低调大师

【Windows10&amp;nbsp;IoT开发系列】API&amp;nbsp;移植工具

原文: 【Windows10IoT开发系列】API移植工具 Windows 10 IoT Core 中是否提供你的当前 Win32 应用程序或库所依赖的 API? 如果不提供,是否存在可使用的等效 API? 此工具可以为你回答这些问题,并协助你将你的当前 Win32 应用程序和库迁移到 Windows IoT Core。 Windows 10 IoT 核心版 API 移植工具可在ms-iot/iot-utilities github 存储库中找到。下载存储库zip并将 IoTAPIPortingTool 文件夹复制到本地计算机。在 Visual Studio 2015 中打开IoTAPIPortingTool.sln并生成项目。这将生成IotAPIPortingTool.exe。 可通过运行IoTAPIPortingTool.exe [-os]使用该工具。 应提供你的 exe 和/或 dll 文件所在的目录的路径。 如果你不计划使用 UWP,应指定 -os 。默认情况下,该工具针对 WindowsUWP 平台验证你的二进制文件。 Note:IoTAPIPortingTool.exe must be run from a Visual Studio​Developer Command Prompt. 该工具将生成名为IoTAPIPortingTool.csv (如果已指定操作系统则为IoTAPIPortingToolOS.csv)的逗号分隔的值 (csv) 文件,并且摘要将在命令行上。在 Excel 中打开 .csv文件来分析完整输出。 声明:本文主要资料来源为Windows 开发人员中心。

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

用户登录
用户注册