调度不一定要有 master:让所有 worker 去抢一个「只能有一个成功」的节点就行。这篇用 create 的原子性做两件事 —— 无 master 的任务抢占,以及多实例部署时的定时任务单实例执行 —— 并在执行中途杀进程,看任务怎么被接走。
完成 300 / 300,用时 4.3 s;执行次数 >1 的任务:[];各 worker 抢到的任务数 {'W0': 62, 'W1': 56, 'W2': 63, 'W3': 60, 'W4': 59}这是分布式锁最简单的形态:每个任务一个节点名,只有一个 create 能成功。和有 master 的方案相比没有单点,但每个 worker 都要扫描 /tasks,任务多时目录大(见大目录)。
第一次 START 由 W1 开始;我在 START 后 0.0 s 时 kill -9 它 第二次 START(接手者):W3,在 kill 后 3.6 s;END 在 kill 后 6.6 s,由 W3 完成;/done/slow00 的写入者 = W3 slow00 一共 START 2 次、END 1 次 —— 至少一次执行:被杀的那一次做了一半,任务必须幂等
claim 是临时节点,所以崩溃的 worker 持有的任务在会话过期后自动释放。因为无法区分「还没开始」和「做了一半」,只能提供至少一次的语义。完成标记 /done 是在任务做完之后才写的。
kill -9 N0(前 10 个 tick 它执行了 5 次)
25 个 tick:被执行的 25 个,漏掉 [],重复执行 [];各实例执行数 {'N0': 5, 'N1': 9, 'N2': 11}
执行时刻相对 tick 整点的偏差(ms):中位 10,最大 16每个 tick 用一个持久节点占位,谁先 create 成功谁执行。要注意:如果抢到的实例在 create 之后、执行完之前崩溃,这个 tick 就丢了(节点已存在,别人不会再做)—— 我没有测这种情况。需要「一定执行」就要像上面的 claim 一样用临时节点加完成标记。所有实例在同一台机器上,时钟没有偏差;跨机器要考虑时钟差。