VIP是虚拟的IP地址,并不对应于一个实际的物理网络接口。经过为一台机器提供备用故障转移选项,VIP可用于提供链接冗余。node
如今经常使用keepalived来实现VIP,结构图以下 bash
在master和backup没法正常通行时(好比master和backup之间网络出现问题),backup会认为master已经挂掉,从而选举本身成为master,开始履行master的职责,对外广播GARP和VRRP报文。这时旧的master依然在正常工做,那么咱们在子网内将有两个主机在同时告诉其余主机:“我是192.168.1.2。”这就是“脑裂问题”。微信
通常采用两个办法来防止脑裂问题。网络
VRRP是一种典型的2N冗余,每每须要两个或以上的实例来保证单个VIP的高可用。可是在实际工程中,多个VIP同时出问题可能性是比较低的,在这种状况下,若是能用N+M(M<N)冗余来达到效果无疑能达到节省成本的效果。运维
利用keepalived其实也能够获得部分N+M的效果,以下图所示。这种方式须要注意配置文件的编写,这无疑也意味着运维成本的增长。工具
本文会提出一种方法利用zookeeper来解决脑裂和成本问题,同时提供一些工具来帮助管理VIP。下面用ZVIP来指代这种方法。ui
总体设计比较简单,以下图所示: spa
如今探讨这些不一样的角色以及每一个角色须要执行的确切步骤。设计
假设要建立地址为192.168.1.2和192.168.1.3的VIP,以下图所示。其中192.168.1.4(node1),192.168.1.5(node2)和192.168.1.5(node3)为实际的IP地址,在node1,node2和node3上运行agent。master运行在主机example.com上。3d
如今有了一个group,这个group里有2个VIP和3个节点。这个group中有两个角色
下面经过zkCli工具来演示工做的流程。
建立/groups, /nodes, /tasks这些znode。
[zk: localhost:2181(CONNECTED) 0] create /groups ""
Created /groups
[zk: localhost:2181(CONNECTED) 1] create /nodes ""
Created /nodes
[zk: localhost:2181(CONNECTED) 4] create /tasks ""
Created /tasks
[zk: localhost:2181(CONNECTED) 5] ls /
[groups, nodes, zookeeper, tasks]
复制代码
当一个agent服务起来时,会在/nodes下注册一个znode而且watch建立的znode。也会在/tasks下执行一样的操做。
# For node1
[zk: localhost:2181(CONNECTED) 7] create /nodes/node-192-168-1-4 ""
Created /nodes/node-192-168-1-3
[zk: localhost:2181(CONNECTED) 9] ls /nodes/node-192-168-1-4 true
[]
# For node1
[zk: localhost:2181(CONNECTED) 7] create /tasks/node-192-168-1-4 ""
Created /nodes/node-192-168-1-4
[zk: localhost:2181(CONNECTED) 9] ls /tasks/node-192-168-1-4 true
[]
复制代码
一个group老是被手动建立。建立者必定知道VIP的地址而且会知道真实机器的信息。建立者经过master来设置一个group(经过ui界面或者调用接口)。
master建立一个znode /groups/group1;而后在各个node下建立这个group。
# For master
[zk: localhost:2181(CONNECTED) 10] create /groups/group1 ""
Created /groups/group1
[zk: localhost:2181(CONNECTED) 11] create /groups/group1/vips ""
Created /groups/group1
[zk: localhost:2181(CONNECTED) 12] create /groups/group1/nodes ""
Created /groups/group1/nodes
[zk: localhost:2181(CONNECTED) 13] create /groups/group1/vips/vip-192-168-1-2 some-config
Created /groups/group1/vips/vip-192-168-1-2
[zk: localhost:2181(CONNECTED) 14] create /groups/group1/vips/vip-192-168-1-3 some-config
Created /groups/group1/vips/vip-192-168-1-3
[zk: localhost:2181(CONNECTED) 15] create /nodes/node-192-168-1-4/group1 some-config
Created /nodes/node-192-168-1-4/group1
[zk: localhost:2181(CONNECTED) 16] create /nodes/node-192-168-1-5/group1 some-config
Created /nodes/node-192-168-1-5/group1
[zk: localhost:2181(CONNECTED) 17] create /nodes/node-192-168-1-6/group1 some-config
Created /nodes/node-192-168-1-6/group1
复制代码
node1由于以前监听了*/nodes/node-192-168-1-4这个节点,因此会接受到zookeeper的通知,node1去读取/nodes/node-192-168-1-4下面的znode,更新本身的配置。而后在/groups/group1/nodes*下去建立一个临时znode。
# For node1
WATCHER::
WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/nodes/node-192-168-1-4
[zk: localhost:2181(CONNECTED) 18] create -e -s /groups/group1/nodes/node-192-168-1-4 ""
Created /groups/group1/nodes/node-192-168-1-4
[zk: localhost:2181(CONNECTED) 19] ls /groups/group1/vips
[vip-192-168-1-2, vip-192-168-1-3]
[zk: localhost:2181(CONNECTED) 20] ls /groups/group1/vips/vip-192-168-1-2 true
[]
[zk: localhost:2181(CONNECTED) 21] ls /groups/group1/vips/vip-192-168-1-3 true
[]
复制代码
当master为*/groups/group1/vips*下面的节点增长子节点时,agent会获得zookeeper的通知,经过获取节点的内容,能够知道本身是否是被master选中,从而选择是否去执行VIP的职责。
如今master向node1发送命令,须要node1去执行。流程以下。 master在*/tasks/node-192-168-1-4*下建立znode,而且监听其变化
# For master
[zk: localhost:2181(CONNECTED) 5] create -s /tasks/node-192-168-1-4/task- "job definition"
Created /tasks/node-192-168-1-4/task-0000000000
[zk: localhost:2181(CONNECTED) 6] ls /tasks/node-192-168-1-4/task-0000000000 true
[]
复制代码
node1以前已经监听过了*/tasks/node-192-168-1-4*,因此会获得zookeeper的通知,这时node1会去读取*/tasks/node-192-168-1-4下面的节点,拿到要执行的任务,在执行完成后,在/tasks//tasks/node-192-168-1-4/task-0000000000*中添加一个状态znode
# For agent
[zk: localhost:2181(CONNECTED) 5] create /tasks/node-192-168-1-4/task-0000000000/status "done"
Created /tasks/node-192-168-1-4/task-0000000000/status
复制代码
master由于监听了/tasks/node-192-168-1-4/task-0000000000节点,因此会接到zookeeper的通知,知道任务已经完成。
VIP由master选择,master会从*/groups/group1/nodes中获取nodes列表,并选择一个node,向其发送一个任务,告诉其让来执行VIP的职责;node执行完成后通知上面的方式告知master任务完成,同时在/groups/group1/vips/vip-192-168-1-3下注册一个临时节点。master会监听这个/groups/group1/vips/vip-192-168-1-3*这个节点,在node挂掉的时候master就能获取通知。
要处理master挂掉的状况,咱们须要有一个备份的master。当主master挂掉的时候,备份master会接管。
由于只有一个进程能成为为master,因此master进程必须经过某种方式不让其余master获取master权限。
每一个master启动时,会在/masters/下建立一个临时节点。当节点建立成功,其余尝试建立同名znode的master会报错,就此得知master这个角色已经被占有的。其余的master会监听这个znode。也会和主master同样监听/groups和/tasks下面的节点。
# For master example.shopee.com
[zk: localhost:2181(CONNECTED) 11] create /masters/master-shopee-com:1212 ""
Created /masters/master-shopee-com:1212
复制代码
master每次执行分配任务时,必须确认本身的master身份。
当一个agent挂掉时,好比node1挂掉时,/groups/group1/nodes/node-192-168-1-4这个临时节点会被删除,master会获得zookeeper 的通知,从而开始选择新的节点做为VIP。
,欢迎你们关注个人微信公众号《派森公园》。