ZooKeeper 的 ZAB 协议和 Leader 选举是怎么工作的?
简化版
ZAB(ZooKeeper Atomic Broadcast,原子广播协议) 是 ZooKeeper 保证数据强一致的核心协议。集群角色分 Leader(唯一,处理写)、Follower(处理读、参与选举和投票)、Observer(只读,不参与投票)。写流程:所有写请求由 Leader 处理,Leader 把写操作作为提案(Proposal)广播给 Follower,收到超过半数Follower 的 ACK 后,Leader 发 Commit 提交——类似两阶段提交,保证多数节点数据一致。Leader 选举:Leader 宕机后,集群进入选举,节点间比较 ZXID(事务 ID,越大数据越新)和 myid,选出数据最新的节点当新 Leader,选举期间集群不可用。
详细版
集群角色:
| 角色 | 职责 | 参与投票 |
|---|---|---|
| Leader | 唯一,处理所有写请求、发起提案广播 | 是 |
| Follower | 处理读请求、转发写给 Leader、参与选举和提案投票 | 是 |
| Observer | 只处理读、不参与投票(用于扩展读性能) | 否 |
ZAB 写流程(消息广播,类 2PC):
1. 写请求到达 Leader(若到 Follower 会转发给 Leader)
2. Leader 生成事务 Proposal(带全局递增的 ZXID),广播给所有 Follower
3. Follower 收到后写入本地日志,返回 ACK
4. Leader 收到【超过半数】ACK → 发送 Commit → 各节点提交
5. 超过半数确认即成功(不需要全部),保证多数一致
Leader 选举(崩溃恢复模式):
- Leader 挂了 → 进入选举 → 比较 ZXID(大者优先,数据最新),ZXID 相同比 myid(大者优先)。
- 获得超过半数投票的节点成为新 Leader。
- 选举期间集群不对外服务(CP 的体现)。
完整版教学
一、ZAB 协议的两种模式
ZAB(ZooKeeper Atomic Broadcast) 是 ZooKeeper 专门设计的一致性协议,保证「所有节点以相同顺序应用相同的写操作」,从而数据强一致。它有两种工作模式:
- 消息广播(Broadcast)模式:正常运行时,Leader 把写请求广播给 Follower,达成多数一致——这是日常的数据同步过程。
- 崩溃恢复(Recovery)模式:Leader 宕机或集群启动时,进入选举,选出新 Leader 并让所有节点数据同步到一致,然后回到广播模式。
理解 ZAB 就是理解这两个模式:正常时怎么同步写(广播)、Leader 挂了怎么恢复(选举)。
二、三种集群角色
ZooKeeper 集群里节点有三种角色:
- Leader(领导者):集群中唯一的写入口。所有写请求都由 Leader 处理,它发起提案、协调多数节点达成一致。
- Follower(跟随者):处理读请求(读可以在任意节点);收到写请求会转发给 Leader;参与 Leader 选举的投票 和 写提案的投票。
- Observer(观察者):只处理读请求,不参与任何投票(选举和提案都不参与)。它的作用是扩展读性能——想加机器提升读能力,但又不想增加投票节点数(投票节点越多,写的多数确认越慢),就加 Observer。
关键:只有 Leader 和 Follower 参与投票,Observer 不参与。「过半数」指的是 Leader + Follower 的数量。
三、写流程:广播提案 + 过半确认(类 2PC)
ZAB 的写流程类似两阶段提交,但只需过半确认(而非全部):
- 写请求汇聚到 Leader:如果写请求发到 Follower,Follower 会把它转发给 Leader(保证所有写都由 Leader 串行处理,从而全局有序)。
- Leader 广播 Proposal:Leader 为这个写操作生成一个事务提案(Proposal),带上全局唯一且递增的 ZXID(事务 ID),广播给所有 Follower。
- Follower 记录并 ACK:Follower 收到提案后,写入本地事务日志(还没真正应用),然后回复 ACK 给 Leader。
- 过半 ACK 则 Commit:Leader 收到超过半数(含自己)的 ACK,就认为提案被多数接受,发送 Commit 消息,各节点正式提交这个写操作。
为什么是「过半」而非「全部」:只要多数节点确认并持久化,数据就不会因少数节点故障而丢失,同时不必等最慢的节点,兼顾了可靠性和性能。这也是为什么 ZooKeeper 集群通常配奇数个节点(3、5 个)——过半更高效(3 个节点过半是 2,容忍 1 个挂;5 个过半是 3,容忍 2 个挂)。
四、ZXID:数据新旧的标尺
ZXID(ZooKeeper Transaction ID) 是一个 64 位、全局递增的事务编号,每个写操作都有一个唯一的 ZXID。它的作用:
- 保证顺序:ZXID 递增,代表了写操作的全局顺序,所有节点按 ZXID 顺序应用写操作,保证一致。
- 标识数据新旧:ZXID 越大,代表数据越新。这在 Leader 选举时至关重要——要选**数据最新(ZXID 最大)**的节点当 Leader,才不会丢数据。
ZXID 高 32 位是 epoch(Leader 的任期编号),每次选出新 Leader,epoch 加 1;低 32 位是该 epoch 内的递增计数。
五、Leader 选举:选数据最新的
当 Leader 宕机(或集群刚启动),进入崩溃恢复模式选举新 Leader:
- 各节点广播投票,投票内容主要包含 (ZXID, myid)。
- 比较规则:先比 ZXID,ZXID 大的优先(数据最新的当 Leader,避免选个数据旧的导致丢数据);ZXID 相同则比 myid(服务器编号),大的优先。
- 每个节点收到别人的投票后,如果对方的 (ZXID, myid) 比自己投的更优,就改投对方。
- 当某个节点获得超过半数的投票,它就成为新 Leader。
- 选出 Leader 后,进入数据同步阶段:Leader 把最新数据同步给所有 Follower,保证大家数据一致,然后恢复对外服务(广播模式)。
选举期间集群不可用:从旧 Leader 挂掉到新 Leader 选出并同步完成,这段时间(通常几十秒内)集群不对外提供服务——这正是 ZooKeeper CP(牺牲可用性保一致性) 的体现。
六、常见误区与追问
这道题面试时最容易丢分的地方,是把「ZooKeeper Zab 与选举」答成一段泛泛的组件介绍。更稳的答法是先给结论,再沿着 服务注册与发现链路 拆清楚流程,最后补上异常场景、数字边界和选型取舍。
| 回答层次 | 要讲清的内容 | 容易漏掉的边界 |
|---|---|---|
| 核心定义 | Zab 保证 ZooKeeper 集群写入顺序一致,Leader 负责提议,Follower 按多数派确认后提交 | 不要停在名词解释 |
| 流程机制 | 客户端写请求到 Leader -> Leader 生成事务提议 zxid -> Follower 写日志并 ACK -> 多数派 ACK 后提交 -> Leader 故障触发新 Leader 选举 | 说明谁触发、谁存储、谁通知、谁兜底 |
| 工程取舍 | 3 节点集群需要 2 个节点形成多数派;Leader 故障后重新选举,少于多数派时集群不能对外提交写入 | 注册信息不是业务数据,短暂不一致通常靠客户端缓存、重试和健康检查兜底 |
ZooKeeper Zab 与选举 面试拆解:
1. 客户端写请求到 Leader
2. Leader 生成事务提议 zxid
3. Follower 写日志并 ACK
4. 多数派 ACK 后提交
5. Leader 故障触发新 Leader 选举
记忆钩子:先区分注册、发现、心跳、剔除和本地缓存,再说明一致性与可用性的取舍;回答时一定要落到题目中的「ZooKeeper Zab 与选举」,不要把相邻中间件的能力混着讲。
- 误区:Zab 和 Paxos/Raft 完全一样。 它们都解决一致性,但 Zab 面向 ZooKeeper 的主备原子广播和崩溃恢复流程。
- 误区:只要有一个 ZooKeeper 节点活着就能写。 写入需要多数派确认,3 节点至少 2 个可用。
- 误区:Leader 选举只看节点编号。 选举会比较 epoch、zxid、server id 等信息,目标是选出日志最新的节点。
- 追问:zxid 有什么作用? zxid 标识事务顺序,帮助恢复时判断日志新旧和提交顺序。
- 追问:为什么 ZooKeeper 适合做强一致协调? 因为它通过 Zab、多数派和有序节点提供一致视图。
- 追问:Leader 挂了服务发现会怎样? 选举期间写入不可用或受阻,读和已有客户端会受会话状态影响。
七、加强记忆
ZAB 协议(ZooKeeper 原子广播)保证强一致,两种模式:消息广播(正常同步写)+ 崩溃恢复(选举)。角色:Leader(唯一、处理写、发提案)、Follower(读+转发写+投票)、Observer(只读、不投票,扩展读性能)。写流程(类 2PC,过半确认):写都汇聚到 Leader → Leader 广播带 ZXID 的 Proposal → Follower 写日志回 ACK → Leader 收过半 ACK 就 Commit(故集群配奇数节点)。ZXID 全局递增,既定顺序又标数据新旧。Leader 选举:比 ZXID(大者优先,数据最新)、相同比 myid,获过半票者当选,选举期间集群不可用(CP 体现)。口诀:Leader 广播提案、过半确认提交、ZXID 定新旧、选举选最新、选举期不可用。