zookeeper当配置为群集模式,在启动或异常状况将被选举为的例子Leader。默认选择算法FastLeaderElection
。java
不知道zookeeper够考虑这样一个问题:某个服务可以配置为多个实例共同构成一个集群对外提供服务。其每一个实例本地都存有冗余数据,每一个实例都可以直接对外提供读写服务。在这个集群中为了保证数据的一致性,需要有一个Leader来协调一些事务。那么问题来了:怎样肯定哪个实例是Leader呢?算法
问题的难点在于:分布式
- 没有一个仲裁者来选定Leader
- 每一个实例本地可能已经存在数据,不肯定哪一个实例上的数据是最新的
分布式选举算法正是用来解决问题的。post
本文基于zookeeper 3.4.6 的源代码进行分析。FastLeaderElection算法的源代码全部位于FastLeaderElection.java
文件里,其对外接口为FastLeaderElection.lookForLeader
,该接口是一个同步接口,直到选举结束才会返回。相同由于网上已有相似文章,因此我就从图示的角度来阐述。阅读一些其它文章有利于得到初步印象:.net
- 深刻浅出Zookeeper之五 Leader选举。代码导读
- zookeeper3.3.3源代码分析(二)FastLeader选举算法。文字描写叙述较细
主要流程
阅读代码和以上推荐文章可以把整个流程梳理清楚。线程
实现上,包含了一个消息处理主循环,也是选举的主要逻辑。以及一个消息发送队列处理线程和消息解码线程。主要流程可归纳为下图:code
推荐对比着推荐的文章及代码理解。不赘述。blog
咱们从感性上来理解这个算法。接口
每一个节点,至关于一个选民,他们都有本身的推荐人,最開始他们都推荐本身。队列
谁更适合成为Leader有一个简单的规则,好比sid够大(配置)、持有的数据够新(zxid够大)。
每一个选民都告诉其它选民本身眼下的推荐人是谁。相似于出去搞宣传拉拢其它选民。每一个选民发现有比本身更适合的人时就转而推荐这个更适合的人。最后。大部分人意见一致时,就可以结束选举。
就这么简单。
总体上有一种不断演化逼近结果的感受。
固然。会有些特殊状况的处理。
好比总共3个选民,1和2已经肯定3是Leader,但3还不知情,此时就走入LEADING/FOLLOWING
的分支,选民3仅仅是接收结果。
代码中不是所有逻辑都在这个大流程中完毕的。
在接收消息线程中。还可能单独地回应某个节点(WorkerReceiver.run
):
从这里可以看出。当某个节点已经肯定选举结果再也不处于LOOKING
状态时。其收到LOOKING
消息时都会直接回应选举的终于结果。结合上面那个例如。至关于某次选举结束了,这个时候来了选民4又发起一次新的选举,那么其它选民就直接告诉它当前的Leader状况。至关于,在这个集群主从已经就绪的状况下,又开启了一个实例,这个实例就会直接使用当前的选举结果。
状态转换
每个节点上有一些重要的做用结构:
- 当前推荐人。初始推荐本身。每次收到其它更好的推荐人时就更新
- 其它人的投票集合。用于肯定什么时候选举结束
每次推荐人更新时就会进行广播,正是这个不断地广播驱动整个算法趋向于结果。
若是有3个节点A/B/C,其都尚未数据,依照sid关系为C>B>A,那么依照规则。C更可能成为Leader,其各个节点的状态转换为:
图中。v(A)表示当前推荐人为A。r[]表示收到的投票集合。
可以看看当其它节点已经肯定投票结果时,即再也不是LOOKING
时的状态:
代码中有一个特殊的投票集合outofelection
,我理解为选举已结束的那些投票,这些投票仅用于表征选举结果。
当一个新启动的节点增长集群时。它对集群内其它节点发出投票请求。而其它节点已不处于LOOKING
状态,此时其它节点回应选举结果。该节点收集这些结果到outofelection
中,终于在收到合法LEADER消息且这些选票也构成选举结束条件时,该节点就结束本身的选举行为。注意到代码中会logicalclock = n.electionEpoch;
更新选举轮数
完