分布式与一致性协议之ZAB协议(三)

ZAB协议

主节点崩溃了,怎么办?

众所周知,系统在运行中不可避免会出现各种各样的问题,比如进程崩溃了、服务器死机了,这些问题会导致很严重的后果,让系统没办法继续运行。在ZAB协议中,写请求是必须在主节点上处理的,而且提案的广播和提交也是由主节点来完成的。既然主节点那么重要,如果它突然崩溃(宕机)了,该怎么办呢?

答案是选举出新的领导者(也就是新的主节点)。

在我看来,领导者选举关乎节点故障容错能力和集群可用性,是ZAB协议非常核心的设计之一。想象一下,如果没有领导者选举,主节点故障了,那么整个集群将无法写入,这将是极其严重的灾难性故障。理解领导者选举(也就是快速领导者选举,Fast Leader Election),能帮助我们更深刻地理解ZAB协议,也能在日常工作中更游刃有余地处理集群的可用性问题。比如写请求持续失败时,可以先排查下集群的节点状态。

既然领导者选举这么重要,那么ZAB协议是如何选举领导者的呢?

ZAB协议是如何选举领导者的

既然要选举领导者,那就会涉及成员身份变更,那么ZAB协议支持哪些成员身份呢?

如何选举





为了更好地理解ZAB的领导者选举,仍然用一个例子演示一下。为了方便演示和理解(我们聚焦最核心的领导者PK),假设投票信息的格式是<proposedLeader,proposedEpoch,proposedLastZxid,node>,具体如下:

  • 1.proposedLeader:节点提议的领导者的集群ID,也就是在集群配置(比如myid配置文件)时指定的ID
  • 2.proposedEpoch:节点提议的领导者的任期编号
  • 3.proposedLastZxid:节点提议的领导者的事务标识符的最大值(也就是最新提案的事务标识符)
  • 4.node:投票的节点,比如节点B.

假设一个ZooKeeper集群由节点A、B、C组成,其中节点A是领导者,节点B、C是跟随者(为了方便演示,假设节点B、C的epoch分别就是1和1,lastZxid分别是101和102,集群ID分别为2和3),如图所示。如果节点A宕机了,如何选举领导者呢?

首先,当跟随者检测到连接领导者节点的读操作等待超时时,跟随者会将自己的节点状态变更成LOOKING,然后发起领导者选举(为了演示方便,我们假设这时节点B、C都已经检测到了读操作超时),如图所示。

接着,每个节点会创建一张选票,这张选票是投给自己的,也就是说,节点B、C都"自告奋勇"地推荐自己为领导者并创建选票<2,1,101,B>和<3,1,102,C>,然后各自将选票发送给集群中的所有节点,也就是说,节点B发送给节点B、C,节点C也发送给节点B、C.

  • 一般而言,节点会先接收自己发送给自己的选票(因为不需要跨节点通信,传输速度更快),也就是说,节点B会先收到来自节点B的选票,节点C会先收到来自节点C的选票,如图所示。
    需要注意的是,集群的个节点收到选票后,为了选举出数据最完整的节点,对于每一张接收到的选票,节点都需要进行领导者PK,也就是将选票提议的领导者和自己提议的领导者进行比较,找出更适合作为领导者的节点。约定的规则如下:
  • 1.优先检查任期编号,任期编号大的节点作为领导者
  • 2.如果任期编号相同,则比较事务标识符的最大值,值大的节点作为领导者
  • 3.如果事务标识符的最大值也相同,再比较集群ID,集群ID大的节点作为领导者。
    如果选票提议的领导者比自己提议的领导者更适合作为领导者,那么节点将调整选票内容,推荐选票提议的领导者作为领导者。
    当节点B、C接收到选票后,因为选票提议的领导者与自己提议的领导者相同,所以,领导者PK的结果是节点B、C不需要调整选票信息,只需要正常接收和保存选票就可以了,如图所示。

接着节点B、C分别接收到来自对方的选票,比如节点B接收到来自节点C的选票,节点C接收到来自节点B的选票,如图所示。

对于节点C而言,它提议的领导者是节点C,而选票(<2,1,101,B>)提议的领导者是节点B,因为节点C的任期编号与节点B相同,但节点C的事务标识符的最大值比节点B的大,所以,按照约定的规则,相比节点B,节点C更适合作为领导者,也就是说,节点C不需要调整选票信息,正常接收和保存选票就可以了。但对于节点B而言,它提议的领导者是节点B,选票(❤️,1,102,C>)提议的领导者节点是C,因为C的任期编号与节点B相同,但节点C的事务标识符的最大值比节点B的大,所以,按照约定的规则,相比节点B,节点C应该作为领导者,也就是说,节点B除了接收和保存选票信息,还会更新自己的选票为<3,1,102,B>,即推荐节点C作为领导者,并将选票重新发送给节点B、C,如图所示。

接着,当节点B、C接收到来自节点B的新的选票时,因为这张选票(❤️,1,102,B>)提议的领导者,与它们提议的领导者是一样的,都是节点C,所以,它们正常接收和保存这张选票就可以了,如图所示。

最后,因为此时节点B、C提议的领导者(节点C)赢得了大多数选票(两张选票),所以,节点B、C将根据投票结果变更节点状态,并退出选举。比如因为当选的领导者是节点C,那么节点B将变更为FOLLOWING并退出选举,而节点C将变更状态为LEADING并退出选举,如图所示。

至此,我们就选举了新的领导者(节点C).这个选举的过程很容易理解,这里只是假设了一种选举的情况,实际上还会存在节点间事务标识符相同、节点在广播投票信息前接收到其他节点的投票等情况。

相关推荐
Yhame.17 分钟前
Java 集合框架中的 List、ArrayList 和 泛型 实例
java
coding侠客17 分钟前
Spring Boot 多数据源解决方案:dynamic-datasource-spring-boot-starter 的奥秘
java·spring boot·后端
委婉待续23 分钟前
java抽奖系统(八)
java·开发语言·状态模式
weixin_537590451 小时前
《Java编程入门官方教程》第八章练习答案
java·开发语言·servlet
技术路上的苦行僧1 小时前
分布式专题(8)之MongoDB存储原理&多文档事务详解
数据库·分布式·mongodb
龙哥·三年风水1 小时前
workman服务端开发模式-应用开发-后端api推送修改二
分布式·gateway·php
CodeClimb1 小时前
【华为OD-E卷-最左侧冗余覆盖子串 100分(python、java、c++、js、c)】
java·python·华为od
Q_19284999062 小时前
基于Spring Boot的大学就业信息管理系统
java·spring boot·后端
小小工匠2 小时前
分布式协同 - 分布式事务_2PC & 3PC解决方案
分布式·分布式事务·2pc·3pc