网络共享复制合作:



我有一个网络服务器,它有一个公开一组文件的共享。这些文件由运行在多台服务器上的进程使用,有时是同一台机器上的几个进程。

该文件集每天更新几次,并且该文件集相当大。

我们正试图通过使同一台计算机上的进程共享相同的文件集来减少这些进程检索这些文件集所使用的带宽。

为了做到这一点,我们希望同一台机器上的每个进程与需要相同文件的其他进程协调,这样只有一个进程会尝试下载文件,然后文件将在完成后由所有进程共享。

此外,我们需要防止服务器在下载过程中对文件集执行更新。

为了满足这个需求,我创建了一个文件锁类。此类在指定位置打开一个名为.lock的文件。文件以读/写方式打开,这样无论进程在哪台机器上运行,它都会阻止另一个进程执行同样的操作。这包含在try/catch中,这样,如果文件已经锁定,则会捕获异常,并且不会获取锁。这已经正常工作了。

我试图解决的问题是,如果一个进程在拥有锁时由于某种原因挂起,那么所有其他进程都将无限期地无法同步这些文件,因为它们无法获取锁。

我们今天正在探索的一个解决方案是使用多锁设置,其中每个锁的名称中都有一个guid,并且可以根据请求获取任意数量的锁,而不是争夺单个硬锁。然而,进程将负责确保在开始下载时只有一个锁集。这样,如果有锁的进程挂起,我们可以认为它在一定的时间限制后过期,并且没有什么可以阻止新进程请求挂起的锁之外的锁。

这里的问题是,这些多锁的创建需要在进程之间同步,否则在创建和检查锁计数时可能存在竞争条件。

如果不像第一个解决方案那样重新引入硬锁定机制,我看不出有什么方法可以同步这一点,但后来我们又回到了开始的地方,挂起的进程会阻止其他进程进行下载。

有什么建议吗?

解决这一问题的一种常见方法是使用某种可共享的锁定文件,通过内容执行真正的锁定逻辑。例如,考虑一个只有一个表的SQlite数据库文件作为锁文件:类似

CREATE TABLE lock (
  id INTEGER PRIMARY KEY AUTOINCREMENT, 
  host TEXT,
  pid INTEGER,
  expires INTEGER
)
  • 使用者(或文件集更新的生产者)通过INSERT进入表来请求锁定
  • 进程通过UPDATE对自己的行进行心跳,使其永不过期
  • 过期的行被丢弃:崩溃的进程将停止更新,最终它们的锁将被丢弃
  • 最低的id持有锁
  • 同一主机上的进程可以评估host字段,以确定同一主机中的另一个进程是否已经想要复制,从而使请求另一个副本变得过时

当然,如果可行的话,这可以通过数据库服务器(或者实际上是锁定服务器)而不是数据库文件来完成,但SQlite方法的优点是只需要文件访问。

这里的诀窍是很好地利用缓存。

指定的更新文件集的"下载"进程应该首先从远程位置获取文件集,并将其存储在临时文件中。然后,它应该继续尝试获取要替换的本地文件的读/写锁定。成功后,进行交换并解除锁定。这部分应该进行得非常非常快。

此外,在本地驱动器上进行简单的文件复制时,不太可能"挂起"。这意味着其他依赖的过程将能够继续运行,无论这一过程发生了什么。

为了确保下载过程正常运行,你需要一个监控程序,每隔一段时间就会对下载过程进行ping,以确保它的响应。如果不是,那么提醒某人。。

最新更新