bigywater.tech
ZooKeeper · 81

Master 选举与工作节点管理

Master 选举不只是「选出一个」,还要让 master 能管理 worker:发现 worker 加入和死亡、重新分配任务、自己挂了之后备用 master 能无缝接手。这篇用 kazoo 搭一个最小的 master/worker,杀 worker、杀 master,数任务有没有丢、有没有重复。

300 / 300
kill -9 一个 worker 后全部完成的任务
0 次
重复执行次数(完成时用 create 判重)
3.3 s
kill -9 master 后备用 master 接管的时间

结构与正常运行

实测 · 本机执行输出
  /workers = ['W1', 'W2', 'W3'] | /master-election 子节点数 = 2
  1.2 秒后:已完成 72 / 300

所有状态都在 ZooKeeper 里:/workers(worker 的临时节点)、/tasks(待分配)、/assign/<worker>(已分配未完成)、/done(已完成)。选举复用上一篇的 Election。把任务从 /tasks 移到 /assign 用 multi,保证任务不会同时在两处或两处都没有。

worker 挂了

实测 · 本机执行输出
  master 日志里的事件: ['+3.6s WORKER_LOST W2 requeued=76']
  最终 /done 里 300 / 300 个任务;重复执行 0 次;全部完成用时 7.1 s
  各 worker 完成的任务数: {'W3': 135, 'W2': 23, 'W1': 142}

worker 的临时节点随会话过期消失,master 比较前后两次的 worker 列表发现它死了。重复执行是靠 worker 完成时 create /done/t 判重(已存在则放弃)来避免的;但「任务做了一半副作用已发生」这种情况 ZooKeeper 管不了,要靠任务本身幂等。

master 挂了

实测 · 本机执行输出
  MASTER_START 事件(相对 kill): ['M1@+-10.0s', 'M2@+3.3s']
  最终 /done = 500 / 500;重复执行 0 次;总用时 7.1 s

新 master 启动时从 ZooKeeper 读出状态继续分配。需要诚实说明我这个最小实现的一个漏洞:新 master 的 known(已知 worker 集合)从空开始,所以在 master 空窗期内死掉的 worker,它的 /assign 目录不会被回收。我没有去测这种情况(因此没有验证);真实实现应该在接管时扫描 /assign 下所有没有对应 /workers 节点的目录。

分步演示

Master / Worker
本步的对象

    本文用到的工具与边界

    • 本机 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;master、worker 都是独立子进程;任务分配按任务名哈希到当前 worker;会话超时 3 s
    • 没有验证:master 空窗期内 worker 死亡的任务回收(见正文的漏洞说明)、任务执行到一半崩溃的副作用、worker 数量动态大幅变化、任务数远大于 300 时 /tasks 的 get_children 成本(见第 23 篇)
    京ICP备2026067502号-1京公网安备11010502063487号