【问题标题】:Platform independent file locking?平台无关的文件锁定?
【发布时间】:2010-10-14 16:15:21
【问题描述】:

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

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

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

【问题讨论】:

    标签: file-io concurrency locking d samba


    【解决方案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); 
    

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

    【讨论】:

    • 你肯定漏掉了他说他需要在不同计算机之间同步的部分。
    • 为什么这行不通?我的意思不是在每台计算机本地编写文件,而是在所有计算机的一个位置。
    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

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

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

      【讨论】:

      • 我不认为 rm 是 Linux 中的原子操作
      【解决方案4】:

      稍微锁定文件

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

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

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

      1. 检查是否存在锁文件

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

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

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

      另一种解决方案

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

      NFS 问题

      好的,我要添加一些内容,因为 Jiri Klouda 正确指出 NFS uses client-side caching 将导致实际的锁定文件处于未确定状态。

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

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

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

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

      • 不要使用 NFS,而只使用 Samba:有一个 good article on the subject 以及为什么 NFS 可能不是您使用场景的最佳答案。
        您还将在本文中找到锁定文件的各种方法。

      • Jiri 的解决方案也不错。

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

      不同的东西

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

      【讨论】:

      • 此解决方案虽然在单台计算机上运行良好,但由于 NFS 客户端缓存会遇到竞争条件。
      • 请注意,NFSv4 修复了旧版本协议的许多问题。
      【解决方案5】:

      为什么不直接在文件和其他计算机之间构建一个简单的服务器?

      如果你想改变数据格式,你只需要修改服务器,而不是所有的客户端。

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

      【讨论】:

      • 或者只是使用数据库并将数据存储在适当的数据库中并解决锁定问题。
      • 我没有配置数据库,也不想为了解决这么简单的问题而配置一个。
      猜你喜欢
      • 2015-11-20
      • 1970-01-01
      • 1970-01-01
      • 2016-09-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多