想象一下几台nix机器的网络。专用节点存储文件并定期调度Task A
以修改这些文件。每个其他节点都会调度Task B
,将这些文件同步(rsync
)到本地存储。
Task A
可能需要相当长的时间,并且文件集合需要在所有节点上处于一致状态。因此Task B
在Task A
运行时不应运行。
可能的解决方案是使用读写器锁。 Task A
和Task B
将分别对资源进行写入和读取锁定。
我想知道如何使用unix shell脚本实现这种锁定机制。
答案 0 :(得分:1)
通常的方法是使用flock
utility,这是util-linux软件包的一部分。 FreeBSD和NetBSD软件包也可用,aiui和其他软件包。 (对于MacOSX,请参阅this question。)
flock
命令可以执行读(“共享”)锁定和写入(“独占”)锁定。它基于flock(2)
系统调用,因此合作锁定(也称为建议锁定),但在大多数应用程序中都能正常工作(但请参阅下面的情况,其中文件很遥远。)
上面的链接手册页中有一些用法示例。最简单的用例是
flock /tmp/lockfile /usr/local/bin/do_the_update
flock /tmp/lockfile -s /usr/local/bin/do_the_rsync
两者都获得了对/tmp/lockfile
的锁定,然后执行指定的命令(可能是一个shell脚本)。第一个命令获得独占锁;我可以使用-x
选项明确说明。第二个命令获取共享锁。
由于问题实际上涉及网络锁的需要,因此有必要指出flock()
在网络文件系统上可能不可靠。通常,目标文件应始终为本地文件。
即使在非分布式应用程序中,您也需要考虑失败的可能性。例如,假设您在本地进行rsync以创建副本。如果主机在rsync处理过程中崩溃,您将最终得到一个不完整或损坏的副本。 rsync可以从中恢复,但不确定当主机重新启动时,rsync将在文件被修改之前启动。这应该不是问题,但你肯定需要考虑它。
在分布式应用程序中,情况更复杂,因为整个系统很少会失败。您可以使不同服务器或网络本身发生独立故障。
咨询锁定不是持久性的。如果锁定文件的主机在保持锁定并重新启动时崩溃,则重新启动后将不会保持锁定。另一方面,如果其中一个持有锁的远程服务器崩溃并重新启动,则可能不知道它正在持有锁,在这种情况下,永远不会释放锁。
如果两个服务器100%了解彼此的状态,这不会有问题,但很难区分网络故障和主机故障。
您需要评估风险。与本地情况一样,如果文件服务器在rsync正在进行时崩溃,它可能会重新启动并立即开始修改文件。如果远程rsync在文件服务器关闭时没有失败,它们将继续尝试同步,并且生成的副本将损坏。使用rsync,这应该在下一个同步周期自行解决,但在此期间您遇到了问题。你需要决定这有多严重。
您可以通过使用持久锁来阻止文件服务器在启动时启动mutator。每个rsync服务器在启动rsync之前在主机上创建自己的锁文件(并且在知道该文件存在之前不启动rsync)并在释放读锁之前删除该文件。如果rsync服务器重新启动并且其指示符文件存在,则它知道rysnc期间发生了崩溃,因此它必须删除指示符文件并重新启动rsync。
这在大多数当时都可以正常工作,但如果rsync服务器在rsync期间崩溃并且从不重新启动,或者仅在很长时间后重新启动,则它可能会失败。 (或者,等效地,如果网络故障长时间隔离rsync服务器。)在这些情况下,可能需要手动干预。在文件服务器上运行监视程序进程会很有用,如果读取锁定被保持太长时间,则会向操作员发出警报,因为某些定义“太长”。