网络共享副本合作:

时间:2013-11-20 01:02:35

标签: c# multithreading

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

这组文件每天更新​​几次,文件集相当大。

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

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

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

为了促进这个要求,我创建了一个文件锁类。此类在指定位置打开名为.lock的文件。该文件以读/写方式打开,因此无论进程运行的是什么机器,它都会阻止其他进程执行相同操作。它包含在try / catch中,因此如果文件已被锁定,则会捕获异常并且不会获取锁定。这已经正常工作了。

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

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

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

如果不重新引入像第一个解决方案那样的硬锁定机制,我没有看到同步这种方法的方法,但是我们回到了我们开始的地方,挂起的进程会阻止其他人下载。

有什么建议吗?

2 个答案:

答案 0 :(得分:0)

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

CREATE TABLE lock (
  id INTEGER PRIMARY KEY AUTOINCREMENT, 
  host TEXT,
  pid INTEGER,
  expires INTEGER
)
  • 使用者(或文件集更新的生产者)通过INSERT请求锁定
  • 一个进程心跳由UPDATE自己的行,使其永不过期
  • 过期的行被丢弃:崩溃的进程将停止更新,最终将丢弃其锁定
  • 最低的ID持有锁
  • 同一主机上的进程可以评估host字段以查找,如果同一主机上的另一个进程已经想要复制,则使其过时以请求另一个副本

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

答案 1 :(得分:0)

这里的诀窍是充分利用缓存。

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

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

为确保下载过程正常运行,您需要一个监控程序,每隔一段时间就会对下载过程进行一次调整以确保其响应能力。如果不是那么警告某人......