8

我正在执行一项计算量非常大的科学工作,时不时地吐出结果。这项工作基本上只是模拟同一件事一大堆时间,所以它被分配给几台使用不同操作系统的计算机。我想将所有这些实例的输出定向到同一个文件,因为所有计算机都可以通过 NFS/Samba 看到同一个文件系统。以下是约束:

  1. 必须允许安全的并发追加。如果另一台计算机上的其他实例当前正在附加到文件,则必须阻止。
  2. 性能不算。每个实例的 I/O 每分钟只有几个字节。
  3. 简单确实很重要。这样做的全部意义(除了纯粹的好奇心)是这样我就可以停止让每个实例写入不同的文件并手动将这些文件合并在一起。
  4. 不能依赖于文件系统的细节。必须在 NFS 或 Samba 挂载上使用未知文件系统。

我使用的语言是 D,以防万一。我看过,标准库中似乎没有任何东西可以做到这一点。特定于 D 的和一般的、与语言无关的答案都是完全可以接受和赞赏的。

4

5 回答 5

8

通过 NFS,您会遇到一些客户端缓存和过时数据的问题。我以前写过一个独立于操作系统的锁模块来工作在 NFS 上。创建 [datafile].lock 文件的简单想法不适用于 NFS。解决它的基本思想是创建一个锁定文件 [datafile].lock,如果存在则意味着文件未锁定,并且想要获取锁定的进程将文件重命名为不同的名称,例如 [datafile].lock。[主机名].[pid]。重命名是一个足够原子的操作,在 NFS 上运行良好,可以保证锁的排他性。其余的基本上是一堆故障安全、循环、错误检查和锁检索,以防进程在释放锁并将锁文件重命名回 [datafile].lock 之前死亡

于 2009-03-20T23:53:42.293 回答
2

经典的解决方案是使用锁定文件,或者更准确地说是锁定目录。在所有常见的操作系统上,创建目录是一个原子操作,所以例程是:

  • 尝试在固定位置创建具有固定名称的锁定目录
  • 如果创建失败,请等待一秒钟左右,然后重试 - 重复直到成功
  • 将您的数据写入真实数据文件
  • 删除锁定目录

多年来,CVS 等应用程序已在许多平台上使用它。唯一的问题发生在极少数情况下,即您的应用程序在写入时和移除锁之前崩溃。

于 2009-03-21T00:03:29.353 回答
2

扭转锁定文件

就像其他答案提到的那样,最简单的方法是在与数据文件相同的目录中创建一个锁定文件。

由于您希望能够通过多台 PC 访问同一个文件,因此我能想到的最佳解决方案是仅包含当前写入数据文件的机器的标识符。

所以写入数据文件的顺序是:

  1. 检查是否存在锁定文件

  2. 如果有一个锁定文件,通过检查它的内容是否有我的标识符来查看我是否是拥有它的人。
    如果是这种情况,只需写入数据文件,然后删除锁定文件。
    如果不是这种情况,只需等待一秒钟或一小段随机时间,然后再次尝试整个循环。

  3. 如果没有锁定文件,请使用我的标识符创建一个并再次尝试整个循环以避免竞争条件(重新检查锁定文件是否真的是我的)。

除了标识符,我会在锁定文件中记录一个时间戳,并检查它是否早于给定的超时值。
如果时间戳太旧,则假设锁定文件已过时并删除它,因为这意味着写入数据文件的 PC 之一可能已崩溃或其连接可能已丢失。

另一种解决方案

如果你在控制数据文件的格式,可以在文件的开头保留一个结构来记录它是否被锁定。
如果您只是为此目的保留一个字节,您可以假设,例如,这00意味着数据文件没有被锁定,而其他值将代表当前写入它的机器的标识符。

NFS 的问题

好的,我要添加一些内容,因为 Jiri Klouda 正确地指出NFS 使用客户端缓存,这将导致实际的锁定文件处于未确定状态。

解决这个问题的几种方法:

  • noac使用orsync选项挂载 NFS 目录。这很容易,但不能完全保证客户端和服务器之间的数据一致性,因此可能仍然存在问题,尽管在您的情况下它可能没问题。

  • O_DIRECT使用、O_SYNCO_DSYNC属性打开锁定文件或数据文件。这应该完全禁用缓存。
    这会降低性能,但会确保一致性。

  • 可能可以使用flock()锁定数据文件,但其实现参差不齐,您需要检查您的特定操作系统是否实际使用 NFS 锁定服务。否则它可能什么都不做。
    如果数据文件被锁定,那么另一个打开它进行写入的客户端将失败。
    哦,是的,它似乎不适用于 SMB 共享,所以最好还是忘记它。

  • 不要使用 NFS,而只使用 Samba:有一篇关于该主题的好文章以及为什么 NFS 可能不是您使用场景的最佳答案。
    您还将在本文中找到锁定文件的各种方法。

  • Jiri 的解决方案也不错。

基本上,如果您想保持简单,请不要将 NFS 用于在多台机器之间共享的频繁更新的文件。

有些不同

使用小型数据库服务器将数据保存到并完全绕过 NFS/SMB 锁定问题,或者保留当前的多个数据文件系统,只需编写一个小实用程序来连接结果。
它可能仍然是解决您的问题的最安全和最简单的解决方案。

于 2009-03-21T00:15:32.723 回答
2

为什么不建立一个简单的服务器,它位于文件和其他计算机之间?

然后,如果您想更改数据格式,您只需修改服务器,而不是所有客户端。

在我看来,构建服务器比尝试使用网络文件系统要容易得多。

于 2009-03-21T02:33:44.797 回答
1

我不知道 D,但我认为使用互斥文件来完成工作可能会奏效。以下是一些您可能会觉得有用的伪代码:

do {
  // Try to create a new file to use as mutex.
  // If it's already created, it will throw some kind of error.
  mutex = create_file_for_writing('lock_file');
} while (mutex == null);

// Open your log file and write results
log_file = open_file_for_reading('the_log_file');
write(log_file, data);
close_file(log_file);

close_file(mutex);
// Free mutex and allow other processes to create the same file.
delete_file(mutex); 

因此,所有进程都会尝试创建互斥文件,但只有获胜的进程才能继续。编写输出后,关闭并删除互斥锁,以便其他进程可以执行相同操作。

于 2009-03-20T23:35:27.143 回答