zookeeper选举机制

选举机制

zxid

zxid:事务编号(zookeeper transaction id),8字节的整型数字,但是zk把这个数字拆成了两部分,64位整数分为前32位和后32位。

初始化的时候zxid是0,即:

00000000000000000000000000000000 00000000000000000000000000000000

每一次写请求都会增加后32位,假设现在进行了10次写请求(即使没有修改到数据)zxid:

00000000000000000000000000000000 00000000000000000000000000001010

当进行一次选举的时候,前 32 位就会增加 1,并且清零后 32 位,此时zxid:

00000000000000000000000000000001 00000000000000000000000000000000

此外,当后32位彻底用完,即zk正常执行了 2^32-1 次写请求都没有进行过一次选举,则前32位加1,此时zxid:

# 进位前
00000000000000000000000000000000 11111111111111111111111111111111
# 进位后
00000000000000000000000000000001 00000000000000000000000000000000

总结:

  • zxid事务编号的前32位官方命名为epoch,表示纪元,含义就是完成了一次leader的选举,或者写操作次数达到了一次上限
  • zxid事务编号的后32为表示节点写操作的次数

myid

zk官方启动配置zoo.cfg中有一项dataDir指定了数据存放的路径(默认是/tmp/zookeeper)搭建zk集群时要在此路径下新建一个文本文件,命名为myid,文本内容就是一个数字,这个数字就是当前节点的myid。

此外在zoo.cfg中配置的信息有:

server.1=zoo1:2888:3888
server.2=zoo2:2888:3888
server.3=zoo3:2888:3888

其中server.之后的数字就是myid,zk中要求myid各不相同(类似于主键)。

选举规则

leader的选举完全看这三个值的大小:

  • epoch(前32位)
  • 写请求次数(后32位)
  • myid

谁大就更有资格成为leader,如果相同则逐级比,因为myid一定不同,所以一定可以分出胜负。

可以看出选举的原则是:

  • 谁当leader的次数多谁先当
  • 谁被请求写操作多,表示谁拿到的数据最新,谁先当
  • 都相同比较myid

虽然我们说要让epoch先比,写请求次数后比。但其实只要比zxid就好了,因为先比epoch大小,再比写请求次数大小这个行为,在数值上等价于直接比zxid。

选举前

三个节点组成的集群对外开始服务前必须选出leader,在选举之前要求:

  • 每个节点必须已知集群中一共有多少个节点
  • 每个节点都在内部维护一个投票箱(表)进行计票
  • 每个节点都有唯一不重复的myid
  • 每次投票后节点会把选票信息发送给集群上所有的节点

zk中节点的状态有:

  • LOOKING:正在寻找leader,处于此阶段的节点不能对外提供服务
  • LEADING:当前节点就是leader,可以对外提供服务
  • FOLLOWING:当前节点是follower,可以对外提供服务

发送个其他节点的选票信息:

  • sid:我是谁
  • leader:我选谁
  • state:我当前状态
  • zxid:我选择的leader的最大事务编号

首次选举leader

设myid分别为1,2,3,4,5节点依次启动

1节点启动

第一次启动,彼此之间没有通信过,每个节点都选自己为leader

选票表:

keyvalue
sidmyid:1
leadermyid:1
stateLOOKING
zxid0

1节点把投票信息发送给了其他4个节点,而此时另外4个节点没启动,无法收到1节点的选票,同样其他4个节点也没给1节点发送选票信息。

投票箱:

投票人选择leader
myid:1myid:1
当前节点所选leader的myid:1,它获得的选票来自节点myid:1

由于1节点票数没有达到半数以上,不能选为leader,且集群中没有leader,故1节点状态仍为LOOKING

2节点启动

同样2节点启动后先投给自己

选票表

keyvalue
sidmyid:2
leadermyid:2
stateLOOKING
zxid0

投票箱:

投票人选择leader
myid:2myid:2
当前节点所选leader的myid:2,它获得的选票来自节点myid:2

2节点随后把选票信息发送给集群上的其他节点,此时集群中只有1节点能收到。
收到后1节点会拿2节点选的leader和1节点自己选leader进行比较,依据比较条件,在zxid一样的情况下,更改选票投给myid更大2节点,同时维护1节点的投票箱,并将选票信息发送给集群上的所有节点,此时只有2节点能收到,2节点在比较后在投票箱中维护数据。

此时1节点和2节点中维护的投票箱为:

投票人选择leader
myid:1myid:2
myid:2myid:2
当前节点所选leader的myid:2,它获得的选票来自节点myid:1,myid:2

由于此时2节点虽然有2票但是任然没到半数以上,所以1节点和2节点仍未LOOKING状态

3节点启动

3节点也先投给自己,其中选票信息为:

keyvalue
sidmyid:3
leadermyid:3
stateLOOKING
zxid0

随后3节点把该选票信息发送到集群中的所有节点上,由于只有1节点和2节点启动,只有他俩收到了,收到后1节点2节点会进行比较,同上可知,仍然选择了myid较大的3节点作为新的选举对象,同时把新的选票发送到所有节点,内部更新投票箱,此时1,2,3三个节点中维护的投票箱一致为:

投票人选择leader
myid:1myid:3
myid:2myid:3
myid:3myid:3
当前节点所选leader的myid:3,它获得的选票来自节点myid:1,myid:2,myid:3

此时3节点获得的票数已经超过半数,更新3节点的状态为LEADING。1节点2节点的状态为FOLLOWING。所有节点epoch加1。集群开放对外服务。

4节点5节点启动

由于启动后得知已经选出leader,则新进入的节点自动状态改为FOLLOWING

挂了重选leader

假设3节点宕机,且在新leader选举出来之前3节点没有恢复上线。此时集群内部知道集群内可用机器数量仍在半数以上,依然可以提供服务,但是要暂停服务选举新的leader。

在暂停期间,所有节点都是LOOKING状态,且都会第一次把票投给自己,投完票后会把选票信息发给集群上有所的节点(包括自己),在收集群上节点的选票时,会不断维护内部的投票箱,每一次都zxid、myid大小进行比较,每一次都把票投给较大的那个同时维护投票箱,保证投票箱在集群上是有一致性的。在这个过程中得票率先超过半数的节点将成为新的leader,它的状态改为LEADING,epoch加1。其他节点状态改为FOLLOWING。集群开启对外服务。

如果3节点此时恢复上线,自动成为follower。

如果3节点在新leader选举出来恢复上线,状态位LOOKING,平等参加选举。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值