连载中 9/20

ZAB 协议:ZooKeeper 的灵魂

2026-06-29 · 1861 阅读 · 0 评论 · 0 赞

上篇留的悬念,本篇揭晓

上一篇说 ZooKeeper 的写要「过半确认才算提交」,新 Leader 上任时「已提交的写入必然都在」——这两句承诺背后站着的就是 ZAB(ZooKeeper Atomic Broadcast,原子广播协议)。它把 ZooKeeper 集群的日子分成两种状态过:一切正常时跑消息广播,Leader 故障时切换到崩溃恢复,恢复完再切回广播。两副面孔轮流值班,撑起「锁已发给谁绝不翻供」的承诺。

面孔一:消息广播——一个不堵车的 2PC

正常态的写入流程,结构上神似分布式事务系列第 3 篇的 2PC,但两处关键改造让它不堵车:

客户端写请求 → Leader 分配 zxid,生成 PROPOSAL
  → 并行发给所有 Follower
Follower 收到 → 顺序写日志 → 回 ACK
Leader 收到过半 ACK → 发 COMMIT → 全员应用变更 → 回客户端成功

改造一:过半就提交,不等全体。2PC 卡在任何一台参与者的回执上,慢一拖全堵;ZAB 只要过半点头就放行,慢节点、宕节点不掉链子——付出的是慢节点可能短暂数据落后的代价(读走各节点本地数据,可能读到刚提交前的值)。改造二:每个 PROPOSAL 带全局单调递增的 zxid,Follower 严格按 zxid 顺序落日志——全集群对「第几号决定」的认识永远一致,乱序无从谈起。对比 Redis 主从复制:Redis 是「主库写完即成功,复制异步慢慢追」,ZAB 是「过半记完账才算成功」——第 7 篇丢锁的窗口,在这里被 quorum 门闩焊死了。

zxid:一个数字里藏着朝代与流水

zxid 是 64 位整数,高 32 位是 epoch(朝代号),低 32 位是本朝内的事务计数器。这个设计一箭双雕:比较两个 zxid,先比朝代——朝代新的一票否决;同朝再比流水——流水大的一定更晚。有了这把标尺,集群里任何两个节点对「谁的日志更新」都能秒级达成一致,不需要任何额外通信。

面孔二:崩溃恢复——带朝代号的选举

Leader 失联(宕机、网络分区),Follower 们进入崩溃恢复:发起选票,每个节点先推荐自己(带上自己的 epoch、zxid、myid),收到别人的选票就比一比,epoch 大者胜,同 epoch 则 zxid 大者胜——谁的数据最新谁当 Leader,数据不齐的落后者根本选不上。胜者当选后把 epoch 加一(改朝换代),把自己全套日志同步给众 Follower,同步完成才开门接客。

两条安全承诺在这里兑现:已提交的事务绝不丢——因为提交要求过半 ACK,新 Leader 必然拥有过半中至少一员的全部日志,选「最新者」必然选中它;未提交的事务必然作废——只在一个节点上晃过的 PROPOSAL 选不上 Leader,自然消亡。最微妙的一幕是旧 Leader 复活:网络分区恢复,被隔离的旧 Leader 重出江湖,发现自己手里还是旧 epoch——朝代号小,立刻自降身份当 Follower,把没提交的提案扔掉,向新 Leader 看齐。epoch 就是防脑裂的终审法官:旧朝的圣旨(未过半的提案)在新朝一律作废。

对比项Redis 主从复制ZAB
写入确认主库本地写完即成功过半确认才提交
故障切换可能丢未同步的写入(第 7 篇丢锁)已提交数据必然在新 Leader 上
脑裂处理靠哨兵仲裁,窗口期双主风险epoch 定新旧,旧主自动退位
性能取向极致性能,牺牲强一致强一致优先,吞吐让路

ZAB 的设计哲学用一句话收拢:用「过半点头」换「历史不翻案」,用「朝代更替」防「旧主复辟」。它天生为 ZK 定制,而它的思想在工业界还有一个更流行的通用版本——Raft,etcd 的心脏,第 13 篇再对照细讲。下一篇先享受 ZAB 的红利:手把手看临时顺序节点怎么把分布式锁做成天生公平、自带防死锁。

☕
503

10 年全栈工程师 · 503咖啡馆主理人

#ZAB#ZooKeeper#epoch#zxid#崩溃恢复#消息广播

评论 (0)

热门推荐

连载中 11/22

主从搭建实操:从零配出一主两从

光讲原理不过瘾?手把手搭一主两从:my.cnf 六个参数、复制账号、GTID、CHANGE REPLICATION SOURCE TO、SHOW REPLICA STATUS 验收,附翻车排查清单。

#MySQL#主从复制#GTID#主从搭建#高可用
2026-05-07 · 10101 阅读 · 0 评论 · 0 赞
连载中 16/22

连接池:HikariCP 参数与连接风暴

连接池不是越大越好:8 核机器配 1000 连接反而更慢的数学原理,HikariCP 四个必调参数,maxLifetime 与 wait_timeout 的隐形陷阱。

#MySQL#连接池#HikariCP#maxLifetime#连接风暴
2026-05-10 · 9873 阅读 · 0 评论 · 0 赞
连载中 4/16

缓存穿透:恶意 ID 打穿 MySQL 的四道防线

请求的数据在缓存和数据库里都不存在时,缓存形同虚设。聊聊参数校验、空值缓存、布隆过滤器、限流熔断四道防线的原理与组合打法。

#Redis#缓存穿透#布隆过滤器#高可用
2026-05-16 · 9294 阅读 · 21 评论 · 287 赞