为了确保单个节点上的多个进程非并发执行某些代码,我可以基于某些原子命令(例如ln
或mkdir
)实现咨询锁定,或者我可以使用flock
.
如何确保多个进程非并发执行某些代码多种的节点(即网络上只允许一个运行实例)?我想通过 Linux 上的 bash 或 python 脚本来执行此操作。
我知道我可以使用 NFS 锁定或 Redis,但我不想有这种复杂性开销。可以使用基于公钥的 ssh。我不想有额外的机器充当锁管理器的开销。理想情况下,管理员不需要提名其中一个节点作为锁管理器。我不需要担心法定人数:如果任何节点无法访问,则无需继续执行。
理想情况下,我可以在所有节点上调用一个命令,例如:
distlock --lock --nodes=nodeA,nodeB,nodeC --resource=resourceX || error "can't lock"
...
distlock --unlock --nodes=nodeA,nodeB,nodeC --resource=resourceX
到目前为止,我想到的最好的办法(通过思考和谷歌搜索)是每个节点都遵循以下过程:
- 从配置文件中读取节点列表(该文件将手动创建并复制到所有节点)
- 确定锁管理器节点是节点列表中按字母顺序排列的第一个节点
- 如果当前运行的脚本实例是在确定的锁管理器节点上,然后以通常的方式创建本地锁文件(锁文件中包含 pid)
- 如果当前运行的脚本实例是不是在确定的锁管理器节点上然后:
- fork an
ssh
到确定的锁管理器节点(例如使用coproc
bash) - 让它创建锁定文件并...
- 让它从它的标准输入(将从主脚本中检测)读取一行文本(由于主脚本尚未发送它,所以它还不会接收到该文本,从而使 pid 文件从确定的锁定中保持不陈旧管理节点的观点)
- fork an
- 执行我想要保护的代码
- 释放锁(如果锁定是本地的,则通过删除锁定文件,或者如果锁定是远程的,则将上述文本行发送到分叉的 ssh 并等待其退出)。
这满足了我的需求:如果多个节点并行执行上述代码,那么恰好有一个节点加锁成功,其他节点加锁失败;如果网络连接失败,那么一个节点(自定的锁管理器)可以继续工作,但其他节点则不能(即集群变为半脑,但不是裂脑)。
然而,我想向其他人征求想法,使用简单的易于编写脚本的工具来寻找替代的、更优雅的解决方案。