上一篇已经搭建好了环境,这篇研究下集群是怎么进行选举的。
源码分析:
首先将三台机器的data目录下除了myid之外的都清掉,从零开始启动。
先启动ZK1
然后顺着main阅读源码
org.apache.zookeeper.server.quorum.QuorumPeer#start
org.apache.zookeeper.server.quorum.QuorumPeer#run
开始不停读取收到的选票,并且找出LEADER是谁
org.apache.zookeeper.server.quorum.FastLeaderElection#lookForLeader
该方法就是根据收到选票的情况,执行不同的方法,本处因为是从零启动,所以第一条消息肯定是都在LOOKING:
如果收到的选票中,他说他也正在LOOKING,那么就比较我们两个的票,根据轮次等决定该信谁的,两人商量好后,我再将这个结果广播出去。
选举过程测试和结果:
清空ZK1和ZK2的data目录下的日志,然后先启动ZK1然后启动ZK2,可以从双方的日志中看到双方进行了一些投票交流,最终确定了ZK2是LEADER。我这在日志里加了个可以打印纳秒的时间戳,就可以清晰看到这样的启动顺序投票过程是怎样的,按先后顺序排列如下:
391479069200 ZK1 Adding vote: from=1, proposed leader=1, proposed zxid=0x0, proposed election epoch=0x1
--1号投自己是LEADER并发送给了自己
397054901700 ZK2 Adding vote: from=2, proposed leader=2, proposed zxid=0x0, proposed election epoch=0x1
--2号投自己是LEADER并发送给了自己
397059044000 ZK2 Adding vote: from=1, proposed leader=1, proposed zxid=0x0, proposed election epoch=0x1
--1号投自己是LEADER并发送给了2号
397059869100 ZK1 Adding vote: from=2, proposed leader=2, proposed zxid=0x0, proposed election epoch=0x1
--2号投自己是LEADER并发送给了1号,1号收到消息后发现两个人都在LOOKING,轮次和ZXID都一样,那就信服务器ID大的,所以1号也转投给2号
397060112400 ZK2 Adding vote: from=1, proposed leader=2, proposed zxid=0x0, proposed election epoch=0x1
--1号转投2号是LEADER并发给了2号,2号在这里调用voteSet.hasAllQuorums()会发现已经有节点收到了超过一半也就是3/2的票,所以就会认为选举完成找到了LEADER。
397060227800 ZK1 Adding vote: from=1, proposed leader=2, proposed zxid=0x0, proposed election epoch=0x1
--1号转投2号是LEADER并发给了自己,在这里调用voteSet.hasAllQuorums()会发现已经有节点收到了超过一半也就是3/2的票,所以就会认为选举完成找到了LEADER。
可以发现,上述选举过程中并没有用到ZAB协议。
选举成功后:
找到LEADER后,ZK1修改自己的状态为FOLLOWER(setPeerState(proposedLeader, voteSet);)
ZK1跳出里层循环回到org.apache.zookeeper.server.quorum.QuorumPeer#run
ZK1下一个循环发现自己是FOLLOWER了,
ZK2下一个循环发现自己是LEADER了,
分别执行如下逻辑。下篇文章再来分析了。