当前位置: 首页 > web >正文

Zab协议剖析:崩溃恢复与顺序原子广播

引言

作为分布式协调服务Zookeeper的核心一致性协议,Zab(Zookeeper Atomic Broadcast)通过崩溃恢复模式原子广播模式的双阶段设计,在分布式系统的高可用与强一致性之间实现了精妙平衡。该协议将集群状态划分为领导选举(Leader Election)提案同步(Proposal Sync)两大核心阶段:选举阶段通过Zxid(全局事务ID)的纪元(Epoch)递增机制,确保新主节点始终携带最新数据视图;同步阶段则利用类两阶段提交(2PC)的原子广播流程,将事务请求以严格递增的Zxid顺序固化到多数节点。其独创的事务提案淘汰规则(如旧Leader重启后自动清除未提交提案)与观察者(Observer)角色的引入,既解决了网络分区导致的数据分歧问题,又通过读写分离架构提升了系统的横向扩展能力。这种兼顾故障恢复效率(秒级切换)与顺序一致性的设计,使得Zab协议成为分布式锁、配置中心等场景下数据一致性的黄金标准。

Zab协议

Zab协议是为分布式协调服务Zookeeper专门设计的一种支持崩溃恢复原子广播协议,是Zookeeper保证数据一致性的核心算法。

Zxid组成

Zxid 是 64 位,高 32 位是 epoch 编号,每经过一次 Leader 选举产生一个新的 leader,新的 leader 会将 epoch 号+1,低 32 位是消息计数器,每接收到一条消息这个值+1,新 leader 选举后这个值重置为 0。这样设计的好处在于老的 leader 挂了以后重启,它不会被选举为 leader,因为此时它的 Zxid 肯定小于当前新的leader。当老的 leader 作为 follower 接入新的 leader 后,新的 leader 会让它将所有旧的 epoch 号且未被 commit 的 proposal 清除。

名词解释

三个角色

  • 领导者(leader):负责进行投票的发起和决议,更新系统状态。
  • 跟随者(follower):follower用于处理客户端请求非事务请求,将事务请求转发给leader,在选主和原子广播过程中参与投票。
  • 观察者(observer):observer用于处理客户端请求非事务请求,将事务请求转发给leader,但observer不参与选主和原子广播过程中投票,只同步leader的数据,observer的目的是为了扩展系统,提高读取速度。

Zab协议的特性

  • Zab 协议需要确保,已经在 Leader 服务器上提交(Commit)的事务最终被所有的服务器提交
  • Zab 协议需要确保,丢弃那些只在 Leader 上被提出而没有被提交的事务

原子广播协议(类2PC)

  • leader每个消息生成一个zxid(唯一且递增)。
  • 带有zxid的消息作为一个proposal分发给集群中的每个follower节点。
  • follower节点把proposal这个消息写入日志,返回ack消息。
  • leader收到合法数量(半数以上)的请求ack后,本地执行commit命令同时向所有的follower服务器发送commit消息。

崩溃恢复模式

一旦 Leader 服务器出现崩溃或者由于网络原因导致 Leader 服务器失去了与过半 Follower 的联系,那么就会进入崩溃恢复模式。崩溃恢复包括选举和同步两个过程。

节点状态

looking:寻找Leader服务的状态,处于当前状态后,将会进行Leader选举流程

following:代表当前服务端处于跟随者状态,表明是Follower服务

leading:代表当前服务端处于领导者状态,表明是Leader服务

observing:观察者状态,表明是Observer服务

选举过程

假设有3个节点,当服务器1启动时(状态变为looking),先把票投给自己(0,1),投票格式(zxid,myid),服务器1状态保持为looking。

服务器2启动时(状态变为looking),先把票投给自己(0,2),并把投票信息发送给集群中其他节点,此时服务器1发现服务器2的myid比自己的大,会更换投票改选为服务器2。此时服务器2有2票,票数已经过半当选为leader。服务器2状态变为leading,新leader选举出来后,会发送“New Leader”消息给集群中的所有节点,通知他们谁是新的 Leader。

选举投票时按照zxid、myid顺序进行比较,谁大把票投给谁。

同步过程

同步阶段主要是利用 leader 前一阶段获得的最新 Proposal 历史,同步集群中所有的follower副本(未提交的消息也会同步给所有的follower副本)。

只有当 quorum(超过半数的节点) 都同步完成,准 leader 才会成为真正的 leader。同时follower 只会接收 zxid 比自己 lastZxid 大的 proposal。

什么时候会出现事务请求被丢失呢?

当 leader 收到合法数量 follower 的 ACKs 后,就向各个 follower 广播 COMMIT 命令,同时也会在本地执行 COMMIT 并向连接的客户端返回「成功」。但是如果在各个 follower 在收到 COMMIT 命令前 leader 就挂了,导致其它的服务器并没有提交这条消息。

如何解决已经被处理的事务请求(proposal)不能丢(已经commit的)呢?

选举拥有 proposal 最大值(即 zxid 最大) 的节点作为新的 leader,由于所有提案被 COMMIT 之前必须有合法数量的 follower ACK,即必须有合法数量的服务器的事务日志上有该提案的 proposal,因此zxid最大也就是数据最新的节点保存了所有被 COMMIT 消息的 proposal 状态。

如何解决未被处理的事务请求(proposal)不能再次出现

通过Zxid,旧的 leader 挂了后重启,它不会再被选举为 leader,因为此时它的 zxid 肯定小于当前的新 leader。当旧的 leader 作为 follower 接入新的 leader 后,新的 leader 会让它将所有的拥有旧的 epoch 号的未被COMMIT 的 proposal 清除。

Zookeeper怎么保证顺序一致性的?

客户端在leader节点上先后执行了x=3,x=4请求,那么所有节点上的请求顺序是一致的。要么x=3,x=4,要么x=4,x=3。

Leader节点顺序处理

Zookeeper的Leader节点会按照请求到达的顺序一一进行处理,确保整个集群内的请求顺序一致性。这意味着,如果消息A比消息B先到达,那么Leader会先处理消息A,然后再处理消息B,确保所有节点上的处理顺序一致。

Follower节点顺序处理

Follower节点接收到提案后,如果提案中的ZXID大于Follower当前已提交的最大ZXID,那么Follower将会将该提案记录到持久化存储中,并准备进行提交 。

然而,如果Follower接收到的提案ZXID小于或等于已提交的最大ZXID,Follower将不会处理该提案,因为这表明该提案在发送过程中出现了乱序,而Follower只会按照ZXID的顺序处理提案 。

如果某一个提案未被大多数节点接受,下一个提案可以执行?

假设有一个提案T1未被大多数节点接受,领导者需要决定如何处理下一个提案T2,有两种方案。

  • 重试T1
    • 领导者可以选择重试T1,继续发送T1给跟随者,直到T1被大多数节点接受。
    • 在T1成功提交之前,T2不会被处理。这确保了T1和T2的顺序一致性。
  • 跳过T1,直接处理T2
    • 如果重试T1失败或被放弃,领导者可以生成新提案T2并发送给所有节点。
    • 在这种情况下,领导者会检查所有节点的日志索引,确保T2的编号和位置正确。
    • 领导者通知所有节点跳过T1,直接处理T2,从而保持日志的连续性和顺序一致性。

感谢您的阅读!如果文章中有任何问题或不足之处,欢迎及时指出,您的反馈将帮助我不断改进与完善。期待与您共同探讨技术,共同进步!

http://www.xdnf.cn/news/13560.html

相关文章:

  • JS手写代码篇---手写深拷贝
  • 万字深度解析注意力机制全景:掌握Transformer核心驱动力​
  • PHP性能提升方案
  • Redis的主从复制底层实现
  • 数组方法_push()/pop()/数组方法_shift()/unshift()
  • Springboot中 MyBatis-Flex TableDef 的使用
  • 常见的CAN总线协议面试题
  • 一套基于Apple watch电话手表包含150个覆盖商务、健康、爱好、定位、时钟、挂件的移动端UI界面的psd
  • 多项式求和
  • 复合材料成型工艺
  • 孙宇晨Token 2049高峰对话,技术话题与社会议题相结合
  • SHA-1算法详解:原理、特点与应用
  • ( github actions + workflow 01 ) 实现爬虫自动化,每2小时爬取一次澎湃新闻
  • Yakit 热加载入门学习指南
  • 深入理解 PCIe 协议中 BDF(Bus/Device/Function)分配与管理机制
  • (九)现代循环神经网络(RNN):从注意力增强到神经架构搜索的深度学习演进
  • 广东省省考备考(第二十六天6.11)—言语:语句表达(练习)
  • leetcode_283.移动零
  • 品牌控价需要精准SKU 数据监测
  • 【 WWDC25:新系统,新命名】
  • 五款MySQL 可视化客户端软件
  • 相机--单目相机
  • 《tqdm:让你的代码会“喘气”的神奇进度条!》
  • 性能测试Locust的使用
  • Docker pull时报错:https://registry-1.docker.io/v2/
  • FastAPI基础入门(三)
  • 创客匠人赋能家庭教育行业:从知识分享到IP变现的转型之路
  • 数值偏微分方程的代数骨架:线性代数及其挑战-AI云计算
  • 公司网络变差的解决方法(固定IP地址冲突)
  • Python实现自动化识别蛋白-配体氢键