bigywater.tech
ZooKeeper · 48

ZooKeeper 脑裂问题

「脑裂」指集群分成两半、各自选出 leader、各自接受写入。ZooKeeper 靠多数派规则避免它。这篇把 5 节点集群切成 2 | 3,持续采样所有节点的角色,看会不会同时出现两个 leader。

最大 1
分区期间任一时刻同时是 leader 的节点数(198 次采样)
2 | 3
少数派一侧不能写,多数派一侧能写
恢复后一致
5 个节点 zxid 相同,少数派一侧的写入不会保留

采样角色

实测 · 本机执行输出
  共采样 198 次;任一时刻同时报告 leader 的节点数最大 = 1;出现 ≥2 个 leader 的采样 0 次 
  多数派一侧的客户端写 /from-majority: 成功 (分区后 5358 ms)

采样用 srvr 的 Mode,间隔 100 ms,所以很短(<100 ms)的重叠可能看不到;这是实验方法的局限。理论上旧 leader 在发现失去多数派之前,确实仍认为自己是 leader,但它的任何写都因凑不齐多数派的 ack 而不能提交。

分区后的数据

实测 · 本机执行输出
  连在旧 leader 上的客户端 create /from-minority 的结果: ConnectionLoss
  网络恢复后读:/from-majority → True | /from-minority → False
  各节点 Mode: {'z48-1': 'follower', 'z48-2': 'follower', 'z48-3': 'follower', 'z48-4': 'follower', 'z48-5': 'leader'}
  各节点 Zxid: {'z48-1': '0x300000001', 'z48-2': '0x300000001', 'z48-3': '0x300000001', 'z48-4': '0x300000001', 'z48-5': '0x300000001'}
  各节点上 /from-majority 的数据: {'z48-1': b'y', 'z48-2': b'y', 'z48-3': b'y', 'z48-4': b'y', 'z48-5': b'y'}

分步演示

脑裂
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 / ZooKeeper 3.9.6(brew 安装的 jar,用 java -cp 直接启动自己的实例,OpenJDK 17 Temurin,JVM 堆 128 MiB)/ 本机回环端口 7300+,数据在临时目录;默认 tickTime=2000;计时用 time.perf_counter,数字每次运行会有小幅抖动。5 节点伪集群,tickTime=500、syncLimit=2;分区用 zkl.NetEnsemble 的悄悄丢包模式;采样间隔 100 ms;一次实验
    • 没有验证:更长的分区时间、多次重复(只做了一次)、非对称分区、客户端同时连着两侧(多地址连接串)时的行为、observer 的影响
    京ICP备2026067502号-1京公网安备11010502063487号