ZooKeeper 主备切换原理
核心定义 ZooKeeper 主备切换是指 Leader 节点故障后,集群通过 ZAB 协议重新选举新的 Leader,并在完成事务日志同步后恢复对外服务的过程。其核心目标是保证分布式协调服务在节点故障后仍能维持一致性和可用性。
1. ZooKeeper 集群角色
ZooKeeper 集群通常由多个节点组成,节点角色包括 Leader、Follower 和 Observer。
| 角色 | 是否参与投票 | 主要职责 |
|---|---|---|
| Leader | 是 | 处理写请求、发起事务提议、协调数据同步 |
| Follower | 是 | 参与选举、同步 Leader 事务、处理读请求 |
| Observer | 否 | 同步数据、处理读请求,不参与投票 |
生产环境通常部署奇数个投票节点,例如 3 节点或 5 节点,以便形成过半多数派。
2. ZAB 协议的核心思想
ZAB(ZooKeeper Atomic Broadcast)是 ZooKeeper 保证一致性的核心协议。它主要解决两个问题:
- Leader 选举:当集群启动或 Leader 故障时,选出新的 Leader。
- 原子广播:由 Leader 将写事务按顺序广播给 Follower,并在多数派确认后提交。
ZooKeeper 的写请求必须经过 Leader;读请求可以由 Follower 或 Observer 直接处理。
客户端写请求
↓
Leader 生成事务提议 proposal
↓
Follower 写入事务日志并 ACK
↓
超过半数 ACK
↓
Leader 提交 commit
↓
Follower 应用事务
3. 关键概念
3.1. zxid
zxid 是 ZooKeeper 的事务 ID,用于标识事务顺序。zxid 越大,说明节点上的数据越新。
可以将 zxid 简化理解为:
zxid = epoch + 事务递增编号
其中 epoch 代表 Leader 任期,事务编号代表该任期内的事务顺序。
3.2. myid
myid 是 ZooKeeper 节点 ID。选举时,如果多个节点的 zxid 相同,通常会比较 myid,myid 更大的节点优先。
3.3. quorum
quorum 表示多数派。ZooKeeper 写入和选举都依赖多数派,常见公式是:
quorum = floor(n / 2) + 1
例如:
| 节点数 | 可容忍故障数 | 多数派 |
|---|---|---|
| 3 | 1 | 2 |
| 5 | 2 | 3 |
| 7 | 3 | 4 |
4. 节点状态
ZooKeeper 节点常见状态:
| 状态 | 含义 |
|---|---|
| LOOKING | 正在寻找 Leader,处于选举中 |
| LEADING | 当前节点是 Leader |
| FOLLOWING | 当前节点是 Follower |
| OBSERVING | 当前节点是 Observer |
集群启动或 Leader 故障时,Follower 会进入 LOOKING 状态并发起选举。
5. 初始 Leader 选举流程
集群启动时,所有投票节点通常都处于 LOOKING 状态。
选举流程:
- 每个节点投票给自己。
- 节点之间交换投票信息。
- 比较候选节点的 zxid。
- zxid 更大的节点优先。
- zxid 相同时,myid 更大的节点优先。
- 某个节点获得超过半数投票后成为 Leader。
- 其他节点转为 Follower。
所有节点 LOOKING
↓
交换投票
↓
比较 zxid 与 myid
↓
超过半数节点认可
↓
产生 Leader
选举优先级 数据越新的节点越优先成为 Leader;如果数据新旧程度相同,则节点 ID 更大的节点优先。
6. Leader 故障检测
Follower 会通过心跳机制检测 Leader 是否存活。
关键参数:
| 参数 | 作用 |
|---|---|
tickTime | ZooKeeper 基础时间单位 |
syncLimit | Follower 与 Leader 同步允许的最大 tick 数 |
initLimit | 初始化连接和同步允许的最大 tick 数 |
如果 Follower 在 tickTime * syncLimit 时间内无法与 Leader 正常通信,就可能认为 Leader 不可用,并进入 LOOKING 状态触发重新选举。
7. Leader 故障后的主备切换流程
Leader 故障后的切换流程如下:
Leader 故障
↓
Follower 心跳超时
↓
Follower 进入 LOOKING
↓
集群重新投票选举
↓
选出新 Leader
↓
新 Leader 与 Follower 同步事务日志
↓
集群恢复对外服务
切换期间,写请求通常会短暂不可用;读请求是否可用取决于客户端连接的节点状态和业务一致性要求。
8. 新 Leader 的数据同步
新 Leader 产生后,需要确保 Follower 与自己保持一致。同步方式取决于 Follower 的数据状态。
| 场景 | 处理方式 |
|---|---|
| Follower 少量落后 | 发送缺失事务日志 |
| Follower 数据超前但未提交 | 回滚未提交事务 |
| Follower 落后过多 | 发送快照进行同步 |
数据同步完成后,Follower 才能进入正常服务状态。
9. 为什么需要多数派
多数派机制用于避免脑裂。
如果没有多数派约束,网络分区时可能出现两个 Leader,各自处理写请求,导致数据分叉。
ZooKeeper 要求 Leader 必须获得多数派支持:
3 节点集群:至少 2 个节点形成多数派
5 节点集群:至少 3 个节点形成多数派
因此,少数派分区无法单独选出 Leader,也就不能继续处理写请求。
10. 主备切换中的常见问题
10.1. 频繁重新选举
常见原因:
- 网络抖动。
- GC 停顿过长。
- 磁盘 IO 抖动导致心跳延迟。
tickTime、syncLimit配置过小。
10.2. 写请求短暂失败
Leader 切换期间,客户端写请求可能失败或超时。客户端应具备重试能力,并正确处理会话重连。
10.3. 集群节点数不合理
偶数节点不会提高容错能力。例如 4 节点集群仍然只能容忍 1 个投票节点故障,因为多数派需要 3 个节点。
10.4. Observer 误解
Observer 可以扩展读能力,但不参与投票,不能提升写入多数派容错能力。
11. 与 Kubernetes / etcd 的关系
Kubernetes 默认使用 etcd 存储集群状态,而不是 ZooKeeper。两者都属于分布式协调或一致性存储组件,但生态定位不同。
| 对比项 | ZooKeeper | etcd |
|---|---|---|
| 一致性协议 | ZAB | Raft |
| 常见生态 | Hadoop、Kafka 旧版本、分布式协调 | Kubernetes、云原生控制面 |
| 数据模型 | 树形 znode | KV 存储 |
| Kubernetes 默认使用 | 否 | 是 |
ZooKeeper 在 Hadoop、大数据、旧版 Kafka 和部分分布式系统中仍然常见;Kubernetes 原生控制面主要依赖 etcd。
12. 面试回答模板
标准回答 ZooKeeper 主备切换基于 ZAB 协议。集群启动或 Leader 故障时,节点进入 LOOKING 状态并发起选举。选举时优先比较 zxid,zxid 越大表示数据越新;zxid 相同时比较 myid。获得超过半数投票的节点成为新 Leader。新 Leader 产生后,会与 Follower 进行事务日志同步,落后的节点补日志,存在未提交事务的节点回滚,落后过多时通过快照同步。ZooKeeper 依赖多数派避免脑裂,因此少数派分区不能单独选主处理写请求。
关联文档
- Kubernetes 集群完整高可用落地方案:理解控制面高可用和分布式一致性组件部署。
- K8s 组件详解:理解 Kubernetes 控制面组件与 etcd 的关系。
- Share-nothing 无共享架构:理解分布式系统中的无共享架构和主备切换边界。
- Kafka 高可用架构完整详解:理解 Kafka 与 ZooKeeper / KRaft 的高可用机制差异。
