使用文件实现分布式锁

11

我有一个网络驱动器(Z:\),它被多台Windows计算机共享。是否可以通过在该网络驱动器上创建/删除文件来实现跨机器锁定?

例如,两台计算机A和B同时想要写入具有ID 123的共享资源。

其中一台计算机,比如说A,通过创建空文件Z:\locks\123首先锁定资源。当B看到名称为“123”的锁定文件时,B知道资源123正在被其他人使用,因此必须等待A删除Z:\locks\123才能访问该资源。

这就像多线程中的关键部分,但我想在多台机器上执行它。

我正在尝试使用Python实现。这是我想到的内容:

import os
import time


def lock_it(lock_id):

    lock_path = "Z:\\locks\\" + lock_id
    while os.path.exists(lock_path):
        time.sleep(5)  # wait for 5 seconds

    # create the lock file
    lock_file = open(lock_path, "w")
    lock_file.close()


 def unlock_it(lock_id):

     # delete the lock file
     lock_path = "Z:\\locks\\" + lock_id
     if os.path.exists(lock_path):
         os.remove(lock_path)

这种方式行不通,因为可能有多个进程同时退出等待状态并创建锁文件。

所以,问题是:是否可能在共享存储上实现跨计算机的锁定机制?

2个回答

8

首先,你应该创建一个锁目录而不是一个锁文件。创建一个目录(见os.mkdir)如果该目录已经存在,则会失败,因此你可以这样获取锁:

while True:
    try:
        os.mkdir(r"z:\my_lock")
        return
    except OSError as e:
        if e.errno != 21: # Double check that errno will be the same on Windows
            raise
        time.sleep(5)

其次(这也是“有点”的地方),你需要一种方式来注意持锁人是否已经死亡。一种简单的方法可能是让他们偶尔更新锁目录中的文件。然后,如果客户端发现该文件已经有一段时间没有被更新,他们可以删除目录并尝试获取锁。


1
加入超时怎么样?例如,经过一段时间(比如60秒),锁会自动释放。假设锁定时间不会超过这个超时时间。我可以使用time.time() - os.path.getctime("Z:\my_lock")获取锁定时间,以检查锁是否过期。 - eliang

2
这将不会像你所希望的那样有效。你可能会遇到其他问题,例如网络驱动器消失,这种情况下,所有进程要么被卡住,要么认为没有人持有锁。
我建议你研究一下ZooKeeper之类的工具。你将能够创建同步锁,并在网络故障时进行恢复。分布式锁背后的框架比在网络驱动器上创建文件要复杂得多。

我在考虑使用Memcache或者像Beanstalk这样的队列软件。 - Jesvin Jose

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接