Zookeeper 脑裂是什么?怎么解决?

#中间件#面试八股

Zookeeper 脑裂是什么?怎么解决?

结论先行:脑裂是网络分区后集群出现两个“自认为的主”。ZK 靠 quorum 从机制上避免双写:写提案必须得到过半节点确认,分区少数派凑不齐票数,只能停服。真正要防的不是“两个 Leader”,而是旧 Leader 在隔离期间仍对外提供读、以及客户端连到少数派后的长时间不可用。

一、经典脑裂场景

5 节点集群,机房之间光纤被挖断

  机房 A:node1(Leader) node2 node3     机房 B:node4 node5
  quorum=3,A 侧有 3 台 → 可选举、可写
  B 侧只有 2 台 → 无法选主,拒绝写请求

如果 A 侧只有 2 台:
  两侧都无法达到 3 票 → 整个集群不可写(宁可不可用,不可双写)

ZK 的设计选择是“少数派直接不可用”,这与 Redis 主从切换的取舍相反。

二、为什么不会真的出现两个 Leader

阶段行为
旧 Leader 失联它仍认为自己是 Leader,继续接受客户端连接
旧 Leader 提交写提案需要过半 Follower ACK,隔离后凑不齐,写超时失败
新 Leader 选出分区多数派选出新 Leader,zxid 更大
旧 Leader 恢复发现集群已有更高 zxid 的 Leader,自动降级为 Follower 并同步数据

关键在 zxid:它是单调递增的事务 ID,任何节点恢复后都以最大 zxid 为准,旧状态被覆盖。

三、防护配置

# zoo.cfg
tickTime=2000
initLimit=10
syncLimit=5
# 每个 server 一行,observer 不参与投票
server.1=10.0.0.1:2888:3888
server.2=10.0.0.2:2888:3888
server.3=10.0.0.3:2888:3888
server.4=10.0.0.4:2888:3888:observer
部署原则:
1. 节点数取奇数(3/5/7),跨机架、跨可用区打散
2. 不要把 quorum 全部放在同一台物理机/同一个交换机下
3. Observer 扩展读能力,但不增加投票数
4. 客户端连接串写全量地址,避免只连一个分区

四、和 Redis 脑裂的差别

维度ZKRedis
防双写机制quorum 过半确认默认没有,靠 min-replicas-to-write
分区少数派拒绝服务旧主继续接受写,恢复后数据丢失
数据冲突zxid 大者胜,旧数据被覆盖旧主数据被清空或需人工处理
典型补救无需人工,自动降级需要哨兵/集群模式 + 参数约束

五、怎么验证防护是否有效

演练期望结果
停掉 1 台(5 节点)集群正常,写延迟略升
停掉 3 台写请求失败,客户端报连接异常,无脏写
断开两个机房间网络多数派侧继续服务,少数派侧拒绝写
恢复网络少数派自动同步,zxid 对齐,无冲突

演练时观察三件事:客户端是否快速失败、是否出现双主日志、恢复后数据是否一致。

常见追问

  • 追问:ZK 脑裂会导致数据不一致吗?不会出现双写导致的分叉,但少数派会短时间不可用,客户端要处理连接失败与重连。
  • 追问:为什么不用偶数节点?4 台的 quorum 是 3,容错仍是 1,和 3 台一样,却多一台成本。
  • 追问:Session 超时会不会误判?会。GC 停顿或网络抖动导致心跳丢失,节点被摘除,业务表现为“假死”。调大 sessionTimeout 并监控 GC 可以缓解。

小结

  • 脑裂的本质是分区后出现两个主,ZK 用 quorum 从写路径上堵死。
  • 少数派停服是刻意设计:宁可不可用,不可双写。
  • zxid 单调递增保证恢复后旧状态被覆盖。
  • 防脑裂更多是部署问题:奇数节点、跨故障域、客户端全地址。
笔记加载中…