基本原理
因为只是做下基础知识的讲解,加深对ZK的了解,所以,下面只讲下ZK的两个重要机制
- 监听机制
- 选举机制(ZK集群)
一:监听机制
道人画了下简图(MarkDowm画简图,真香!):
- ZooKeeper 提供了分布式数据发布/订阅功能,一个典型的发布/订阅模型系 统定义了一种一对多的订阅关系,能让多个订阅者同时监听某一个主题对象,当 这个主题对象自身状态变化时,会通知所有订阅者,使他们能够做出相应的处理。
- ZooKeeper 中,引入了 Watcher 机制来实现这种分布式的通知功能。 ZooKeeper 允许客户端向服务端注册一个 Watcher 监听,当服务端的一些事件触 发了这个 Watcher,那么就会向指定客户端发送一个事件通知来实现分布式的通知功能。
- 触发事件种类很多,如:节点创建,节点删除,节点改变,子节点改变等。
道人概括下,就是客户端在ZK上指定节点创建监听(监听的触发条件可以是节点创建,节点删除,节点改变,子节点改变等),一旦节点发生改变触发监听,ZK会通知客户端。
监听机制的特点
- 一次性触发
- 事件发生触发监听,一个watcher event就会被发送到设置监听的客户端, 这种效果是一次 性的,后续再次发生同样的事件,不会再次触发。如果需要再次监听同样的事件,需要再次设置。
- 事件封装
- ZooKeeper 使用 WatchedEvent 对象来封装服务端事件并传递。 WatchedEvent 包含了每一个事件的三个基本属性: 通知状态(keeperState),事件类型(EventType)和节点路径(path)
- event 异步发送
- watcher 的通知事件从服务端发送到客户端是异步的。
- 先注册再触发
- Zookeeper 中的 watch 机制,必须客户端先去服务端注册监听,这样事件发 送才会触发监听,通知给客户端。
道人概括下就是:
- 客户端先注册监听;且监听只会被触发一次(后失效),如果需要再次监听需要再次设置;监听触发后,ZK将通知事件封装后异步传递客户端。
监听的命令操作,javaAPI会在道人的后续博客中介绍。
二:选举机制
ZK集群模式下,选取出Leader的方式,最新的算法是FastLeaderElection(默认),判断依据是选票超过半数则选举成功。
涉及概念
-
服务器ID
- 比如有三台服务器,zk依次启动时会对服务器进行依次编号分别是 1,2,3。 编号越大在选择算法中的权重越大。(全新集群选举时,哪个ZK服务先启动其sessionID越小。)
-
选举状态
- LOOKING,竞选状态。
- FOLLOWING,随从状态,同步 leader 状态,参与投票。
- OBSERVING,观察状态, 同步 leader 状态,不参与投票。
- LEADING,领导者状态。
-
数据ID
服务器中存放的最新数据 version。
值越大说明数据越新,在选举算法中数据越新权重越大。
- 逻辑时钟
也叫投票的次数,同一轮投票过程中的逻辑时钟值是相同的。每投完一次票 这个数据就会增加,然后与接收到的其它服务器返回的投票信息中的数值相比, 根据不同的值做出不同的判断。
选举机制大致流程图
举个栗子
首先道人介绍下选举时几个原则,帮助各位道友理解。
- 每当一个ZK节点加入集群中,获取当前节点的Zxid(也是递增),并使逻辑时钟的值+1,新的ZK节点向其他节点广播的逻辑时钟值大于其保存的逻辑时钟值,表明有新的节点加入集群,便从新开始一次选举。
- 每个新加入节点,会将选票投给自己,同时通知其他节点从新投票,投票原则是,将票投给Zxid最大的节点(也可理解新加入节点)。
- 判断规则为节点选票大于半数,则选择的节点选举为leader,而一旦选举为leader,,自身状态会变为leading,其之前节点状态会有Looking变为Following则后续加入节点,不可能成为leader,只能作为Follower。
再简化说下原则:
- 原则一:选票投最大Zxid节点,**超过半数则选举出Leader。**直到选举出Leader,集群才能正常工作。
- 原则二:节点加入(Looking状态),则开启新一轮选举,其他节点更改选票,根据原则一,判断是否选举出Leader。
- 原则三:Leader选举出来后,选举为Leader的节点状态修改为Leading,其他节点从Looking修改为Following,后续节点均为Follower。
以五个节点的ZK服务集群为例(这里的服务器后1,2,3,4,5;可以理解为zk服务的Zxid)
(1)服务器1启动,发起一次选举。
服务器1投票给自己,发现选票小于半数,无法完成选举。
服务器1状态保持为LOOKING;
(2)服务器2启动,再发起一次选举。
服务器1和2分别投自己一票,此时服务器1发现服务器2的Zxid比自己大,更改选票投给服务器2;
发现选票小于半数,无法完成选举。
服务器1,2状态保持为LOOKING;
(3)服务器3启动,发起一次选举。
服务器1,2,3分别投自己一票,服务器1和服务器2更改选票投给Zxid更大的服务器3;
此次投票结果:服务器1为0票,服务器2为0票,服务器3为3票。此时服务器3的票数已经超过半数(3票),服务器3当选Leader。
服务器1,2更改状态为FOLLOWING,服务器3更改状态为LEADING;
(4)服务器4启动,发起一次选举。
此时服务器1,2,3已经不是LOOKING状态,不会更改选票信息。交换选票信息结果:服务器3为3票,服务器4为1票。
此时服务器4服从多数,更改选票信息为服务器3;
服务器4并更改状态为FOLLOWING;
(5)服务器5启动(情况与服务器5相同);
服务器5并更改状态为FOLLOWING;
上述过程的选举流程图如下:
上述讲解的是全新集群选举(即集群启动时选举的机制),下面介绍下非全新集群选举(集群启动后有节点宕机的情况)。
非全新集群选举
对于运行正常的 zookeeper 集群,中途有节点宕机,需要重新选举时, 选举过程就需要加入数据 ID、服务器 ID 和逻辑时钟。
概念:
- 数据 ID:数据新的 version 就大,数据每次更新都会更新 version。
- 服务器 ID:就是我们配置的 myid 中的值,每个机器一个。
- 逻辑时钟:这个值从 0 开始递增,每次选举对应一个值。 如果在同一次选举 中,这个值是一致的。
选举原则:
- 逻辑时钟小的选举结果被忽略,重新投票;
- 统一逻辑时钟后,数据 id 大的胜出;
- 数据 id 相同的情况下,服务器 id 大的胜出;
其余选举过程等同于全新集群选举。
道友们都看到这了,有收获的话,点个赞再走呗!道人在此谢过了!