bigywater.tech
ZooKeeper · 80

用 ZooKeeper 做 Leader 选举

用 ZooKeeper 给自己的应用(而不是 ZooKeeper 集群本身)选 leader:主备切换、单实例定时任务都靠它。这篇起 5 个候选进程,量选举结果、kill -9 之后的空窗期、有没有两个 leader 重叠,以及主动让位和崩溃的差别。

1 个
同一时刻发心跳的 leader 数(5 个候选)
3.04 s
kill -9 leader 后新 leader 出现的空窗(中位,会话超时 3 s)
0.01 s
leader 正常关闭会话时的切换空窗

选出一个

实测 · 本机执行输出
  当选者: ['A'] | /election 的子节点数 = 5
  同一时刻只有一个在发心跳: True

配方和分布式锁几乎一样:临时顺序节点,序号最小的当选,别人只监听前一个。区别是「锁」被持有一小会儿,「leader」被持有到进程结束。

杀掉 leader

实测 · 本机执行输出
   次   被杀  新 leader        空窗期 s(最后一次心跳 → 新 leader 开始)     期间是否有两个 leader
   1    A         B                               3.52                 没有
   2    B         C                               3.04                 没有
   3    C         D                               3.05                 没有
   4    D         E                               3.03                 没有
  空窗期中位 3.04 s(会话超时 3 s + 选举)

空窗由会话超时决定:leader 被 kill -9 后,服务端要等会话过期才删除它的临时节点,下一个候选才被通知。中间这几秒没有 leader,业务必须能容忍;调小会话超时能缩短,但会增加误切换。

主动让位

实测 · 本机执行输出
  X 当选并在 1.6 秒后让位(进程退出时关闭会话):X 最后一次心跳到 Y 开始 = 0.01 s

进程收到退出信号时先关闭会话(或调用 resign),临时节点立刻删除。发布升级、滚动重启都应该走这条路径。

分步演示

Leader 选举
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 / ZooKeeper 3.9.6(brew 安装的 jar,用 java -cp 直接启动自己的实例,OpenJDK 17 Temurin,JVM 堆 128 MiB)/ 本机回环端口 7300+,数据在临时目录;默认 tickTime=2000;计时用 time.perf_counter,数字每次运行会有小幅抖动。kazoo 2.11.0 的 Election;5 个候选各为独立子进程;「同时有两个 leader」用各进程写的心跳日志的时间区间是否重叠来判断;会话超时 3 s
    • 没有验证:leader 被冻结(不是死亡)后的重叠窗口(与第 79 篇的冻结锁同理,Election 配方没有防护)、网络分区下的 leader、候选数更大时的选举耗时
    京ICP备2026067502号-1京公网安备11010502063487号