前言
Zookeeper
是一款比较常见的式应用程序协调服务软件,如果配置了多台zookeeper
自然要选择一个头头,这个头头就是leader
,很明显不能所有的zookeeper
都是leader
,那样就失控了;也不能所有的zookeeper
都是follower
,那就群龙无首无法协调。
插播一句,这种一老大N跟班
的模式是过去分布式软件里很常见的工作模式,而最近比较火热的区块链不同,它是一种去中心化
的工作模式,大家人人都当节点,然后放在一起整合,有点原始社会的意思。所以说,算法有时候来自于人类学,也会在一定程度反过来上影响人类。
选举leader
的方式是一种叫FastLeaderELection
的算法,以3.4.6
版本为例,它被保存在/usr/zookeeper/src/java/main/org/apache/zookeeper/server/quorum/
这个文件夹下。
选举的中心思想
实际上FastLeaderELection
说的中心思想无外乎以下几个关键点:
全天下我最牛!在我没有发现比我牛的推荐人的情况下,我就一直推举我当
leader
,第一次投票那必须推举我自己当leader
。每当我接收到其它的被推举者,我都要回馈一个信息,表明我还是不是推举我自己。如果被推举者没我大,我就一直推举我当
leader
,是我是我还是我!我有一个票箱, 和我属于同一轮的投票情况都在这个票箱里面。一人一票重复的或者过期的票,我都不接受。
一旦我不再推举我自己了(这时我发现别人推举的人比我推荐的更牛),我就把我的票箱清空,重新发起一轮投票(这时我的票箱一定有两票了,都是选的我认为最牛的人)。
一旦我发现收到的推举信息中投票轮要高于我的投票轮,我也要清空我的票箱。并且还是投当初我觉得最牛的那个人(除非当前的人比我最初的推荐牛,我就顺带更新我的推荐)。
不断的重复上面的过程,不断的告诉别人“我的投票是第几轮”、“我推举的人是谁”。直到我的票箱中“我推举的最牛的人”收到了不少于
N/2 + 1
的推举投票。这也回答了为什么zookeeper
在少于N/2 + 1
的节点处于工作状态的情况下会崩溃了。因为,无论怎么选也没有任何节点能够获得N/2 + 1
的票数。这时我就可以决定我是
flower
还是leader
了(如果至始至终都是我最牛,那我就是leader
咯,其它情况就是follower
咯)。并且不论随后收到谁的投票,都向它直接反馈“我的结果”。
判断依据
上面第二步里说了,如果接收到其他被推举者的消息,而且判断出这个被推举者比我牛,我就要推举他,那么判断依据是啥呢?答案是依次比较epoch
、zxid
、serverid
。
先说说啥是epoch
、zxid
、serverid
:
epoch
: 表示选举轮数。zxid
: 事务zxid包含了本地数据的最后更新时间相关的信息。serverid
: 当前server
的 ID, 通过配置文件指定(echo '1' > myid
)。
具体的判断过程是:接收到的消息中,有epoch
比我大的,则选epoch
大的消息中确定的server
;如果epoch
相等,则选zxid
最大的server
;如果zxid
也相等,则选serverid
最大的server
(有的节点生来就是当leader
的)。
为什么要有epoch
呢?这样是为了防止中途有选举者掉线,他们错过了选举,再次连上来的时候,他们发现自己的投票轮已经小于现有的投票轮了,那么他们比如要清空自己的投票箱然后无条件的改为推荐接收到的最新选举中大家推荐的最牛的那个人(如果没有人比我牛,那还是推荐我自己)。由于有最后一条serverid
大的最后压阵,而且serverid
又不能重复,所以基本上都能最后选出一台作为leader
。
参考资料
http://blog.csdn.net/yinwenjie/article/details/47613309
https://mozillazg.com/2017/03/zookeeper-fastleader-elect-leader.html