ZooKeeper Leader服务器选举流程

进行前提

进行Leader选举的前提是ZooKeeper必须是集群,即至少2台以上ZooKeeper服务器。满足集群的条件后,Leader的选举在以下情况下发生:

  • ZooKeeper服务器进程启动
  • ZooKeeper服务器进程在运行期间无法连接到Leader服务器

注意:“Leader的选举”这个过程是对于单个ZooKeeper服务器进程而言的,并不是整个ZooKeeper服务器集群。当一个ZooKeeper服务器进入Leader选举流程时,可能集群的状态有:

  • 这个集群存在一个Leader服务器并且工作正常
  • Leader尚未被选举出来
  • 当前服务器由于网络故障与Leader服务器断开连接 ,或者Leader服务器宕机

对于第一种情况,通常是当前服务器启动比较晚,在ZooKeeper启动时都会尝试进行Leader选举,在向其它服务器发送投票时,其它服务器会将正确的Leader服务器信息告知当前服务器,忽略其投票信息。

只有后两种情况,集群才会进行完整的Leader选举流程。第二种情况对应初始化时期的选举,第三种情况对应运行期间的选举。这两种选举大同小异,后一种无非就是当Follower检测到Leader挂了后,就会将FOLLOWING状态改为LOOKING,并按照同样的流程发送投票、接收投票、统计投票。

注意Observer身份的ZooKeeper服务器是没有资格参与Leader竞选的。


选举流程

ZooKeeper服务器有4种状态,在源代码中作为枚举定义在org.apache.zookeeper.server.quorum.QuorumPeer.ServerState中:

  • LOOKING:正在寻找Leader服务器
  • FOLLOWING:当前服务器角色为Follower
  • LEADING:当前服务器角色为Leader服务器
  • OBSERVING:当前服务器角色为Observer

在服务器集群刚启动时,此时是没有Leader服务器的,所有的服务器都处于LOOKING状态,并准备进行投票操作。

1、发送投票

每个服务器都会将自身作为Leader服务器来投票,并序列化后发送给各个ZooKeeper服务器,也就是说如果有 n n n 台服务器,那么会存在 n n n 种选票,并发送 n ( n − 1 ) n(n-1) n(n1) 次。投票在源码中的定义是org.apache.zookeeper.server.quorum.Vote,包含5个成员变量:idzxidelectionEpochpeerEpochversion

  • id,即服务器的SID,该值等于配置文件给服务器指定的myid,一个集群中每台ZooKeeper服务器都有一个唯一的SID,不能重复。
  • zxid,服务器的ZXID,也就是事务ID用来标识一次服务器的状态变更,该ID是一个64位数字,高32位为leader epoch,每一次Leader的选举都会将这个数值加上1,低32位为当前epoch的事务变更次数,例如执行一次写入ZNode操作时,就会将这个数加上1,读取ZNode数据则不会,因为不是事务操作。此外该数值会持久化到本地磁盘。同一时刻集群每台服务器的ZXID不一定一致
  • peerEpoch:服务器的leader epoch
  • electionEpoch:用于判断多个投票是否是同一轮的选举。每进行一次Leader选举都会将该值加上1。
  • version:ZooKeeper服务器的版本

其中最为重要的是id字段和zxid字段。

为了方便表述,我们以(SID,ZXID)的形式来标识一张投票,并且当前集群有三台机器,SID分别为0、1、2。
各个服务器会生成一张初始选票,其SID为自身,ZXID也为当前服务器的ZXID,然后将选票投给自己:
在这里插入图片描述
再将选票发送到另外两个服务器。即各个服务器选票为(0,0)(1,0)(2,0)(假设ZXID为0):
在这里插入图片描述
此时各个服务器都有1张初始投票,2张其它服务器发送过来的选票。

2、接收其它服务器的选票

服务器在收到其它服务器的选票后,会校验选票的选举轮次,判断方式为:
根据选票的electionEpoch判断自己给自己投的选票是否一致。如果自己的选票的electionEpoch大于其它服务器发送过来的选票,那么直接丢弃这个选票。如果小于,则代表当前服务器选举轮次已经落后于其它服务器,服务器会立刻清空所有收到的选票,并且更新自己的选举轮次,然后使用初始选票来PK。

校验完成后,会将自己的选票和接收到的选票进行PK:首先会比对其它选票的ZXID和自己的ZXID,如果这些ZXID都互不相等,那么当前服务器会推举ZXID最大的服务器作为Leader。如果各个选票的ZXID都相等,那么推举SID最大的服务器作为Leader服务器,并将初始选票变更为推举的Leader服务器。

对于刚才的例子,显然ZXID都为0,那么会推举SID为2的服务器作为Leader。各个服务器会生成一张(2,0)选票,并发送给其它服务器,如果推举的Leader不是自身,那么会变更自身的初始选票(2,0)

3、统计选票

之后,每个服务器会统计所有投票信息,判断recvset是否有过半的选票(过半指大于 n 2 + 1 \frac{n}{2}+1 2n+1 n n n 为服务器的数量)和初始选票相同(recvset保存了当前服务器收到的所有选票),如果存在过半的选票相同,那么就认为已经选举出了Leader,并且Leader服务器SID为过半选票中的SID。此时如果SID为自身,那么当前服务器就成为了Leader,并将状态由LOOKING改为LEADING,反之为Follower,状态也为FOLLOWING
在这里插入图片描述
注意上图中每个服务器最后都有3张选票,因为recvset是以SID为键,Vote为值的Map,在PK之后,发送的变更选票会将原先阶段2发送的选票覆盖掉。所以说如果某个服务器在阶段2之后宕机,那么该服务器SIDrecvset中的选票并不会被覆盖。上述逻辑在FastLeaderElection中的lookForLeader方法中有所体现,这里就不贴源码分析了。

如果没有接收到过半的选票,那么会尝试重新接收选票,如果服务器发现无法接收任何选票,就会确认自身有没有和其它服务器建立连接,如果连接断开则会重建连接,并再次发送初始选票

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值