0


zookeeper leader 选择详细流程

一、集群启动时候选举的流程

先来看第一种 Leader 选举时机:ZooKeeper 服务启动的时候。

在讲解之前,我先来问你一个问题:为什么集群启动时候会进行选举?很简单,因为刚启动的时候,节点状态都是 LOOKING,寻主状态,而且是刚启动,肯定是无主的,需要选举的,所以肯定需要投票进行 Leader 选举。

假设我们要搭建一个 ZooKeeper 集群,集群内有三个 ZooKeeper 服务,分别为:Zookeeper1、Zookeeper2 和 Zookeeper3。按顺序启动,那么哪台机器最有可能被选举为 Leader 呢?为什么?

我先不说答案,我们先分析下集群启动时候的选举流程,然后我们再反过来看这个问题。

首轮投票都会投给自己,因为集群内彼此不知道各自的 zxid 和 myid 等参数,所以 Zookeeper1、Zookeeper2 和 Zookeeper3 的票箱如下图所示:

由于第一轮,大家都自己投了自己,这时候票箱如下:
服务票箱Zookeeper1(1,1)、(2,2)、(3,3),相当于每人都只有1票,持平Zookeeper2(1,1)、(2,2)、(3,3),相当于每人都只有1票,持平Zookeeper3(1,1)、(2,2)、(3,3),相当于每人都只有1票,持平
现在每个节点的票数都一样,都是 1 票,所以不分胜负,那只能进行下一轮投票了。那下一轮投给谁呢?我们先把上一篇画的图拿出来重新回忆一下选举流程:

按照我们在上一篇中的设计来分析的话,先对比 logicClock,优先投给 logicClock 大的;但是现在发现 logicClock 都一样大,也就是走到了上图中的第 6⃣️ 步骤,开始对比 vote_zxid。

vote_zxid 是什么来着?vote_zxid 就是被推荐服务器上所保存数据的最大 zxid。

但是,现在三个 ZooKeeper 服务都把票投递给了自己,并且因为都是刚启动的,还没处理请求,也是首轮选举,所以它们的 epoch 和事物写次数都是 0,也就是说这三个 ZooKeeper 服务的 zxid 也都一样,都是 0。于是就走到了我们上图中的第 7⃣️ 步骤,开始对比 vote_id。

vote_id 就是被推荐服务器的 myid。

那很明显,Zookeeper3 的 myid 是最大的,所以事情变得简单了,终于有结论了。Zookeeper1 和 Zookeeper2 会将票投给 Zookeeper3,而 Zookeeper3 仍然会投给自己。详细核心流程如下。

  1. Zookeeper1 收到 Zookeeper2 和 Zookeeper3 的投票后,发现三者的 logicClock 和 vote_zxid 都一样,所以只能找最大的 myid 进行选举,发现 Zookeeper3 的 myid 是3,而 Zookeeper2 的 myid 是 2,因此 Zookeeper1 将宝贵的一票投给 Zookeeper3。
  2. Zookeeper2 收到 Zookeeper1 和 Zookeeper3 的投票后,发现三者的 logicClock 和 vote_zxid 都一样,所以只能找最大的 myid 进行选举,发现 Zookeeper3 的 myid 是 3,而Zookeeper1 的 myid 是 1,因此 Zookeeper2 将宝贵的一票也投给 Zookeeper3。
  3. Zookeeper3 同理,将票留给自己。

第二轮投完了,这时候我们看下票箱情况:
服务票箱Zookeeper1(1,3)、(2,3)、(3,3),三个节点都投递给了Zookeeper3Zookeeper2(1,3)、(2,3)、(3,3),三个节点都投递给了Zookeeper3Zookeeper3(1,3)、(2,3)、(3,3),三个节点都投递给了Zookeeper3
所以毫无争议,大家都认为 Zookeeper3 最适合当 Leader,其实我们本来是过半就行,但是目前大家都同意,那自然最好不过了。Leader 选完了,我们接下来需要干什么?

  1. 改状态呀!

现在状态还是 LOOKING 呢,我们需要给 Zookeeper3 改为

  1. LEADING

,而 Zookeeper1 和 Zookeeper2 改为

  1. FOLLOWING

状态,然后 Leader 发起与各个 Follower 之间的心跳。

好了,目前我们已经讲解完第一个选举时机的全流程了,接下来回归到我们最初的问题:集群内有三个 ZooKeeper 服务,分别为 Zookeeper1、Zookeeper2 和 Zookeeper3,

  1. 按顺序启动

,那么哪台机器最有可能被选举为 Leader 呢?为什么?

按照我们上面的分析,好像最后选出来的是 Zookeeper3 这个服务,但最后选出来的 Leader 真的是 Zookeeper3 吗?错!因为我说了按顺序启动,你想想按顺序,也就是先启动 Zookeeper1,然后 Zookeeper1 开始寻主,发现只有自己,不能构成集群,所以不能升级为 Leader;这时候 Zookeeper2 启动了,也开始寻主、投票。开始都会投给自己,但是第二轮的时候 Zookeeper1 发现 Zookeeper2 的 myid 最大,会把票投给 Zookeeper2,那这时候的结果就是 Zookeeper1 零票、Zookeeper2 两票。按照过半原则,已经符合升级为 Leader 的条件,所以这时候 Zookeeper2 就已经被选为 Leader 了。

有人问:那 Zookeeper3 呢?你想一个问题,选主是毫秒级别的,而服务启动是秒级别的,在 Zookeeper3 启动完成之前,Zookeeper2 早就被选为 Leader 啦!因此,这个问题的答案大概率是 Zookeeper2 被选为 Leader!

那还有人问:Zookeeper3 启动完成后咋办呢?它当然也会进行投票,但是投完后发现 Zookeeper1 和 Zookeeper2 都回应已经有Leader了且 Leader 是 Zookeeper2,那么 Zookeeper3 发现过半的人都回复 Leader 是 Zookeeper2,那就不折腾了,直接作为 Follower 追随 Zookeeper2 这个 Leader。

二、Follower 重启投票流程

我们接着看第二个投票时机:Follower 宕机重启了,这时候该怎么办?

在这之前,我先问个问题:Follower 宕机有啥问题?啥问题也没有,无伤大雅!只是少了一台节点对外提供读能力而已,因为只有 Leader 能处理写请求,所以我们先可以明确一点就是 Follower 意外宕机,其实影响范围不是很大。

好了,回归正题:Follower 重启投票流程。

假设 Zookeeper1 重启了,首先 Follower 重启后的状态是 LOOKING,所以会发起投票,且首轮会把票投给自己然后通过网络广播出去,如下图所示:

这时候 Zookeeper2 和 Zookeeper3 收到了 Zookeeper1 的投票,会响应给 Zookeeper1 什么呢?

  • 首先,假设 Zookeeper3 是 Leader,那么 Zookeeper3 会给它回复一个:我就是 Leader,你还投什么?直接变 Follower 给我当小弟。
  • 其次,Zookeeper2 收到 Zookeeper1 的投票后,也会回复一个:Zookeeper3 是 Leader,我是 Follower,在当 Zookeeper3 的小弟,你别投了,已经有 Leader 了,你也一起加入吧。
  • 最后,Zookeeper1 收到其他两台机器的回复后,发现 Zookeeper3 就是 Leader 的票数超过一半了,所以 Zookeeper1 心甘情愿地改为 Follower 给 Zookeeper3 当小弟。

具体过程如下图:

当然不能忘了改状态,给 Zookeeper1 修改状态为 Follower,且 Zookeeper3 会维持 Follower 的心跳。

上面讲解了 Follower 挂了的投票流程,那么如果是 Leader 挂了,该怎么办?

三、Leader 重启投票流程

Leader 挂了就不是那么简单的事情了,相当于老大没了,这时候所有的写请求都无法得到处理,那就是属于亚健康状态了,所以需要进行

  1. 选主

。那怎么选主呢?我不怕啰嗦,再从头到尾以图文结合的方式阐述下。

首先,假设 Zookeeper3 是 Leader,然后它挂了,所以 Follower1 和 Follower2 发现 Leader 挂了(没心跳了),就会进入 LOOKING 状态,重新进行选举。我们先来看下图(Leader 挂了,Follower 进入 LOOKING 状态):

然后,两个 LOOKING 状态的 Zookeeper 要重新发起选举,老规矩,还是先投自己,然后通过网络广播出去。如下图:

接下来又是重复的流程。

  • Zookeeper2 收到 Zookeeper1 的投票,发现二者的 logicClock 和 zxid 都一样,那就对比 myid,结果发现 Zookeeper2 自己的 myid 是大于接收到外部 Zookeeper1 发起的投票的 myid,所以 Zookeeper2 仍然投自己一票并通过网络发给 Zookeeper1。
  • Zookeeper1 同样收到 Zookeeper2 的投票,结果发现二者的 logicClock 和 zxid 都一样,myid 还小于 Zookeeper2 的,那就也将宝贵的一票投给 Zookeeper2。

如下图:

这时候我们看下票箱情况:
服务票箱Zookeeper1(1,2)、(2,2),Zookeeper2两票,Zookeeper1零票Zookeeper2(1,2)、(2,2),Zookeeper2两票,Zookeeper1零票
符合过半原则,所以 Zookeeper2 被选举为 Leader,而 Zookeeper1 成为 Zookeeper2 的 Follower,最后修改各自的状态且在二者之间建立心跳。

看起来好像一切恢复正常了,那如果 Zookeeper3 重新启动了呢?这时候会怎样?

首先 Zookeeper3 重新启动它的状态会变为 LOOKING,所以它会再次投给自己一票,并通过网络广播给其他人,如下:

这时候当 Zookeeper1 和 Zookeeper2 收到 Zookeeper3 的广播后,会给予相应的回应。

  • Zookeeper1 会回复:你别投票了,现在整个集群是有主的,Zookeeper2 就是主,我是追随它的 Follower,你也一起加入吧。
  • Zookeeper2 会回复:我就是 Leader,你想谋权?赶紧当我小弟(Follower)追随我,别找事。

Zookeeper3 收到各位大佬的回复后,发现 Zookeeper1 和 Zookeeper2 都说 Zookeeper2 是 Leader,且集群算上自己就三台机器,符合过半原则了,那就不犹豫了,直接修改自己的状态为 FOLLOWING 去追随 Zookeeper2,然后 Zookeeper2 维护 Zookeeper3 这个 Follower 的心跳。

看到这里,有的同学可能会产生这样一个疑问。假设写请求刚写到 Leader,尚未同步到各个 Follower 呢,然后 Leader 宕机了,接下来其他 Follower 肯定会选出一个新的 Leader。但这时候恰巧新 Leader 刚选出来,还没接收写请求呢,旧 Leader 就恢复了,别忘了旧 Leader 宕机之前是写成功的,所以旧 Leader 的 zxid 肯定大于新 Leader 的,也就是说旧 Leader 的消息更全、更新,那么旧 Leader 恢复后,会顶替新 Leader 吗?

不会!我不管你 zxid 是不是大,你启动回来后就是 LOOKING 寻主状态,但是集群内已经有新的 Leader 了,旧 Leader 只能抹掉数据同步我新 Leader 的。

你想想,如果让你设计一个 ZooKeeper 的选举功能,你考虑一大堆情况,只会造成代码的

  1. 复杂性

  1. 臃肿性

,因此没必要为一些非常见场景而破坏整个优雅的项目,情况很多,考虑不完的,何况目前 ZooKeeper 的设计我个人觉得已经很合理了。

一言以蔽之:Leader 选举有三个时机,集群刚启动、Follower 宕机和 Leader 宕机,核心选举流程就是先对比 logicClock ➡️ 再对比 zxid➡️最后对比 myid,选出 Leader 后修改状态以及建立心跳。


本文转载自: https://blog.csdn.net/zhangVSdj/article/details/140889344
版权归原作者 zhangVSdj 所有, 如有侵权,请联系我们删除。

“zookeeper leader 选择详细流程”的评论:

还没有评论