在上一篇文章中,我们讨论了 Paxos 和 Raft 这两种经典的一致性协议。那么,一个很自然的问题就出现了:ZooKeeper 为什么既不用 Paxos,也不用 Raft?它为什么要自己设计一个 ZAB 协议?
答案其实很明确:ZooKeeper 要解决的,绝不仅仅是“选主”问题。它真正需要保障的,是分布式环境下的原子广播与顺序一致性。
今天,我们就来把 ZAB 协议一次讲透。
一、ZAB 是什么?
ZAB 的全称是:
ZooKeeper Atomic Broadcast
它的核心关键词只有两个:
Atomic(原子性)
Broadcast(广播)
简单来说,ZAB 是一个专门为 “主从架构” 设计的原子广播协议。
请务必注意这个精准的定位:
ZAB = 强 Leader + 原子广播
二、ZooKeeper 要解决什么问题?
首先得明确,ZooKeeper 不是一个数据库。它的典型应用场景包括:
- 配置中心
- 注册中心
- 分布式锁协调器
- 元数据管理系统
这些场景有一个共同的核心要求:顺序一致性。
这是什么意思呢?假设客户端依次执行以下操作:
写A
写B
写C
那么,集群中的所有节点都必须看到完全相同的顺序:A → B → C,绝对不能乱。同时,这些写操作还必须满足原子性,即要么全部成功,要么全部失败。
这就是 原子广播 + 全局有序 的需求。Paxos 或 Raft 主要解决的是“值一致”(Consensus on a value)的问题,而 ZAB 更侧重于保障“事务的顺序一致”。
三、ZAB 的整体架构
ZAB 采用了经典的 Leader + Follower 架构,不存在多个 Leader 竞争写入的情况。
系统正常运行时,状态非常清晰:
1 个 Leader
N 个 Follower
所有的写请求流向是固定的:
客户端 → Leader → 广播给 Followers
四、ZAB 的两种模式
ZAB 协议的运行分为两个核心阶段:
① 恢复模式(Recovery Mode)
当集群初次启动,或者 Leader 节点崩溃时,系统就会进入恢复模式。
这个阶段的主要目标是:
选出新的 Leader
确保数据一致
其核心步骤包括:
- 选举 Leader
- 同步历史事务
- 确保新 Leader 拥有最完整的数据
只有当多数节点完成确认后,系统才会退出恢复模式,进入正常状态。
② 广播模式(Broadcast Mode)
一旦 Leader 被成功选出,系统就进入广播模式。
在此模式下,规则很简单:
所有写请求必须经由 Leader 处理
五、ZAB 写入流程(核心)
让我们跟随一个客户端写请求,看看 ZAB 是如何工作的。
Step 1:Leader 分配事务 ID(ZXID)
Leader 会为每个事务分配一个全局唯一且递增的 ID,称为 ZXID。
ZXID 的格式通常为:
epoch + counter
它的核心作用是保证所有事务的全局顺序。
Step 2:Leader 发送 Proposal
Leader 将包含 ZXID 和数据的提案(Proposal)广播给所有的 Follower。
Proposal(zxid, data)
Step 3:Follower 返回 ACK
每个 Follower 在收到 Proposal 后,会将其写入本地日志,然后向 Leader 返回一个 ACK 确认。
Step 4:多数确认后提交
当 Leader 收到超过半数 Follower 的 ACK 后,便认为该事务已达成共识。随后,Leader 会提交该事务,并广播一个 Commit 消息。
Step 5:所有节点提交
所有的节点(包括 Leader 和 Follower)在收到 Commit 消息后,才会正式将数据应用到状态机中。
至此,整个写入流程完成。
六、ZAB 为什么强调 ZXID?
因为 ZooKeeper 的核心是顺序一致性。ZXID 的存在保证了:
- 所有事务全局有序。
- 即使在崩溃恢复后,事务的顺序也不会乱。
- 新的 Leader 能够准确判断哪个节点的数据是最新的。
你可以把它理解为类似于 Raft 协议中 Log Index + Term 的组合,但 ZXID 的设计更加贴合 ZooKeeper 自身的需求。
七、ZAB 和 Raft 有什么区别?
很多人会有疑问:ZAB 看起来不就是 Raft 吗?其实不然,两者有显著区别。
我们通过一个表格来直观对比:
| 维度 |
Raft |
ZAB |
| 目标 |
通用一致性 |
原子广播 |
| 结构 |
强 Leader |
强 Leader |
| 日志复制 |
多数确认 |
多数确认 |
| 顺序保证 |
有 |
更加强调 |
| 崩溃恢复 |
标准化 |
更复杂的同步过程 |
| 设计目的 |
通用分布式系统 |
专为 ZooKeeper 定制 |
用一句话概括:
Raft = 通用一致性协议
ZAB = 面向顺序广播优化的一致性协议
八、为什么 ZooKeeper 不直接用 Raft?
这背后主要有三个原因:
① 历史时间线
ZAB 协议的设计和实现远早于 Raft:
- ZAB 设计时间:2008 年
- Raft 论文发表时间:2014 年
时间线决定了技术选型。
② 核心诉求不同
Raft 主要关注的是日志的一致性(Log Consistency),而 ZAB 从一开始就聚焦于全局顺序 + 原子广播。ZooKeeper 的核心功能(如 Watch 机制)严重依赖于严格的事务顺序。
③ 恢复机制设计
ZAB 在崩溃恢复阶段的设计比 Raft 更复杂,包含了更重的数据同步过程。这套机制虽然看似繁琐,但却与 ZooKeeper 作为协调服务的读写模型更加匹配。
九、ZAB 的优点
- 强顺序保证:完美满足协调服务的核心需求。
- 适合协调型系统:为配置管理、服务发现等场景量身打造。
- 主从结构清晰:逻辑简单,易于理解和实现。
- 崩溃恢复机制成熟:经过多年生产环境检验。
十、ZAB 的缺点
- 强依赖 Leader:Leader 成为单点性能和瓶颈。
- Leader 压力大:所有写请求都必须经过 Leader。
- 扩展性有限:不太适合需要极高吞吐量的数据存储场景。
- 场景特定:并非像 Raft 那样的通用解决方案。
十一、一句话理解 ZAB
Paxos 解决“值一致”,Raft 解决“工程一致”,ZAB 解决“顺序广播一致”。
十二、总结
ZooKeeper 选择 ZAB,并非因为它比 Paxos 或 Raft 更先进、更高级,而是因为 ZAB 是最适合 ZooKeeper 数据模型和业务场景的协议。
ZAB 的本质是 强 Leader + 原子广播 + 全局顺序。它是一个为“协调型系统”量身定做的专用协议,而非一个追求通用性的一致性协议。理解这一点,就能明白 ZooKeeper 技术栈背后的设计哲学。
如果你对分布式系统底层原理感兴趣,想了解更多类似的技术细节与实践,欢迎到云栈社区与更多开发者一起交流探讨。