Skip to content

ZAB 协议详解


ZAB 是 ZooKeeper Atomic Broadcast 协议的简称,是 ZooKeeper 用来实现分布式一致性的核心算法。

ZAB 协议的核心目标:
1. 消息广播:保证事务的原子性
2. 崩溃恢复:Leader 故障时重新选主
3. 数据同步:新 Leader 与 Follower 数据一致
特性ZABPaxos
角色Leader + FollowerProposer + Acceptor
场景主备复制分布式共识
领导人强领导轮流提议
优化支持崩溃恢复理论性强

┌─────────────────────────────────────────────────────────────┐
│ 消息广播流程 │
├─────────────────────────────────────────────────────────────┤
│ │
│ Client Leader │
│ │ │ │
│ │ 1. 发送写请求 │ │
│ │ ─────────────────────────>│ │
│ │ │ │
│ │ │ 2. 转换为事务 Proposal │
│ │ │ ──────────┐ │
│ │ │ │ │
│ │ │ 3. 广播给所有 Follower │
│ │ │ ─────────┬──────────────┐│
│ │ │ │ ││
│ │ │ ▼ ││
│ │ │ Follower1 ◄─────────────┤│
│ │ │ Follower2 ◄─────────────┤│
│ │ │ │
│ │ │ 4. 收到半数以上 ACK │
│ │ │ ◄────────┬──────────────┤│
│ │ │ │ ││
│ │ │ 5. 提交事务 │
│ │ │ ──────────┐ │
│ │ │ │ │
│ │ 6. 返回成功 │ ▼ │
│ │ <─────────────────────────│ Follower1 ◄────────────┘│
│ │ │ Follower2 ◄────────────┘│
│ │
└─────────────────────────────────────────────────────────────┘
  1. Leader 发起提案:将客户端请求转换为事务 Proposal
  2. 广播给 Follower:Leader 将 Proposal 发送给所有 Follower
  3. 收集 ACK:Follower 收到 Proposal 后写入本地日志,返回 ACK
  4. 半数以上提交:Leader 收到半数以上 ACK 后,提交事务
  5. 同步给 Follower:Leader 通知 Follower 提交事务

ZAB 的消息广播本质上是 2PC(两阶段提交) 的变种:

第一阶段(准备):
Leader 发送 Proposal → Follower 写入日志 → 返回 ACK
第二阶段(提交):
Leader 收到半数 ACK → 发送 COMMIT → 提交事务

  • Leader 宕机
  • 网络分区导致 Leader 与半数 Follower 失联
  • Leader 失去法定票数
┌─────────────────────────────────────────────────────────────┐
│ 崩溃恢复流程 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 新的 Follower 发现 Leader 不可用 │
│ │ │
│ ▼ │
│ 2. 进入 Leader 选举状态 │
│ │ │
│ ▼ │
│ 3. 每个节点投票给自己,推举自己为 Leader │
│ │ │
│ ▼ │
│ 4. 互相通信,交换投票 │
│ │ │
│ ▼ │
│ 5. 选出新的 Leader(获得半数以上投票) │
│ │ │
│ ▼ │
│ 6. 新的 Leader 与 Follower 同步数据 │
│ │ │
│ ▼ │
│ 7. 开始处理客户端请求 │
│ │
└─────────────────────────────────────────────────────────────┘

ZooKeeper 使用 Fast Leader Election(FLE) 算法:

// 投票数据结构
class Vote {
long id; // 投票的 Server ID
long zxid; // 最大的事务 ID
long electionEpoch; // 选举轮次
long state; // 状态
}
选举原则(按优先级):
1. electionEpoch 越大越新(先比较选举轮次)
2. zxid 越大数据越新(再比较事务 ID)
3. id 越大权重越高(最后比较 Server ID)
时间线:
─────────────────────────────────────────────────────────────►
T1: Leader 宕机
T2: Follower1 检测到超时,进入 LOOKING 状态
│ 发送投票 (zxid=100, sid=1)
T3: Follower2 检测到超时,进入 LOOKING 状态
│ 发送投票 (zxid=100, sid=2)
T4: 互相交换投票
│ Follower1 收到 (zxid=100, sid=2)
│ → 更新自己的投票为 (zxid=100, sid=2)
│ Follower2 收到 (zxid=100, sid=1)
│ → 保持投票 (zxid=100, sid=2)
T5: Follower2 获得半数投票,成为 Leader
│ 开始发送心跳
T6: Follower1 收到 Leader 心跳,确认 Follower 角色

类型场景说明
DIFF数据差异小发送差异数据
SNAP数据差异大发送完整快照
TRUNC多余数据截断多余数据
Leader:
1. 计算 Follower 的 zxid
2. 如果差异小 → 发送 DIFF
3. 如果差异大 → 发送 SNAP
4. 如果有多余 → 发送 TRUNC
Follower:
1. 接收同步数据
2. 写入本地日志
3. 更新内存数据
4. 返回 ACK

ZXID = 高 32 位(epoch)+ 低 32 位(counter)
epoch:选举轮次,每选举一次递增
counter:事务计数器,每提交一次递增
例如:0x0000000100000001
→ epoch = 1
→ counter = 1
ZooKeeper Server 状态:
┌─────────┐
│ LOOKING │ 选举中
└────┬────┘
├──> ┌─────────┐ 选举成功 ┌─────────┐
│ │ LEADING │ ─────────► │FOLLOWING│
│ └─────────┘ └─────────┘
└──> ┌─────────┐ 选举失败 ┌─────────┐
│ LEADING │ ◄───────── │FOLLOWING│
└─────────┘ └─────────┘

参考答案

  1. 消息广播:Leader 将事务广播给 Follower,半数以上 ACK 后提交
  2. 崩溃恢复:Leader 故障后重新选主,数据同步
  3. 数据同步:新 Leader 与 Follower 保持数据一致

参考答案

  1. 先比较 electionEpoch(选举轮次),越大越新
  2. 再比较 zxid(事务 ID),越大数据越新
  3. 最后比较 sid(服务器 ID),越大权重越高

参考答案

  1. 所有写请求由 Leader 处理
  2. 写请求转换为事务,通过 2PC 广播
  3. 半数以上 Follower 确认后提交
  4. Leader 故障时,通过选举恢复一致性