让一批进程「等齐了再一起开始」「都做完了再一起结束」,这就是栅栏。ZooKeeper 上有两种配方:单次放行的 Barrier,和进出都同步的 DoubleBarrier。这篇量放行的同步程度、重复使用、人数不齐会怎样,以及参与者崩溃时会怎样。
/bar 存在: True (Barrier 的「关上」就是这个 znode 存在) 1 秒后仍被挡住的等待者数 = 10 remove() 之后 10 个都被唤醒:最早 11.0 ms,最晚 13.3 ms 已经移除后再来的等待者:wait() 立即返回: 0.8 ms
等待者 watch 这个 znode 的删除事件;控制者删掉它就是放行。10 个 watcher 同时被触发(单个路径,惊群规模取决于等待者数量,见watch 风暴)。
p0: 调用 enter 0.0s → 实际进入 2.0s;干活 0.2s,调用 leave 2.2s → 实际离开 3.1s p1: 调用 enter 0.0s → 实际进入 2.0s;干活 0.4s,调用 leave 2.4s → 实际离开 3.1s p2: 调用 enter 0.0s → 实际进入 2.0s;干活 0.6s,调用 leave 2.6s → 实际离开 3.1s p3: 调用 enter 0.0s → 实际进入 2.0s;干活 0.8s,调用 leave 2.8s → 实际离开 3.1s p4: 调用 enter 2.0s → 实际进入 2.0s;干活 1.0s,调用 leave 3.0s → 实际离开 3.1s 进入时刻最大差 0 ms;离开时刻最大差 2 ms
每个参与者在 /dbar 下建一个临时节点;子节点数达到要求人数时进入放行,离开时节点逐个删除、删光时放行。典型用法:一批 worker 等所有人就绪再开始计算、全做完再汇总。
第二轮完成的参与者数 = 5 / 5;/dbar 剩余子节点 = []
4 个都还在等(没有 timeout 参数的 enter 会永远阻塞):已返回 0 个;/dbar3 子节点 4 个 kazoo 的 DoubleBarrier.enter() 没有 timeout 参数,没人来就一直等。
这是用 DoubleBarrier 最容易踩的坑:启动一个参与者失败了,其余的就卡在 enter() 上,没有任何报错。
3 个参与者全部 ENTERED 后 kill -9 其中一个,另外两个 LEFT 的时刻(相对 kill): ['3.6s', '3.6s'](会话超时 3 s)
节点是临时节点,所以崩溃的参与者最终会被清除,leave 不会永远卡住,但要等一个会话超时。对称地,如果参与者在 enter 之前崩溃,其余人则永远等(上一节)。