网上关于 zookeeper FastLeaderElection 的文章很多,但和最新版本的 3.4.5 的代码对照后发现还是存在出入,而且大多语焉不详。
先发一幅和FastLeaderElection相关的示意图上来吧,可能是网上最详细的一幅了。
根据代码,FastLeaderElection 虽然用了TCP作为底层通信架构,但实际上底层通信仍然是 会丢失、会重复、甚至顺序会颠倒(也就是违反FIFO)的 ,可以用另外一种协议(比如UDP)来替换掉。
日后有空可能会写一篇关于版本3.4.5 的FastLeaderElection的算法分析的文章,但也未必会有心情写。
顺便说一下对 ZOOKEEPER源代码的观感。当然写出这样一个软件是很强的,但源代码的风格不算最好,而且同样一个软件里面进行 SOCKET通信的代码其风格相当不统一:处理CLIENT连接的部分使用了SELECT风格,也就是单个线程处理全部SOCKET的模式;leaderElection部分是监听线程 + 每个客户端连接一对读写线程的模式;Leader处理Follwer请求的通信方式还没有看,似乎和leaderElection类似。
但 FastLeaderElection 里面启动的 WorkerReceiver/WorkerSender线程是在 lookForLeader() 被调用前就启动了的,因此 3 个 proposedXXXX 变量(指proposedLeader等3个变量)很可能在 lookForLeader() 开始处的初始化动作没有完成前就被WorkerReceiver 使用了,这个是不是会有一些潜在的问题呢?
self对象的currentVote 和 3个proposedXXXX 变量的关系 以前网上的文章里面没有说得很清楚。应该说currentVote 的内容最终是来自于这3个proposedXXXX变量。而WorkerReceiver 直接应答的时候有时候返回currentVote 的内容,有时候返回 proposedXXXX 3变量,这是因为本节点在looking 状态下时 3变量反映了此刻该节点最新的VOTE;而在其他状态下该节点的VOTE观点并未发生变化,所以最新观点直接就是currentVote了。
logicalclock 和 electionEpoch 应该只是用来在选举过程中产生lamport逻辑时钟偏序关系,和实际zxid 中的 epoch 没有任何关系。