Perl 5.x 文档指出其集群(..)的实现将使用以下本机调用之一,从 1 开始,如果不可用则朝 3 方向努力:
- 羊群(2)
- fcntl(2)
- 锁(3)
没关系。但是,您可能已经注意到他们的免责声明:flock(2) 不应在 NFS 上使用。该文档建议使用 -Ud_flock 标志来强制 Perl 使用集群(2)。 flock(2)(Redhat 上)的手册页声明了有关 NFS 问题的类似免责声明。
我的问题是,为什么!!!我似乎找不到一篇深入的文章或解释为什么集群(2)在 NFS 上不安全。
我已经在Redhat(使用flock(2))和Solaris(使用fcntl(2))上用C 和Perl 编写了几个测试脚本。我运行 strace/truss 来确保 Perl 确实分别使用了 fancy(2) 和 fcntl(2) 。我无法复制任何未遵守锁定的问题!是什么赋予了??
答案1
我很确定您正在考虑遗留问题。回想一下,Perl5 手册于 1994 年发布,它只是 1991 年 Perl4 手册的编辑。在那些日子里,人们可能会说,经常被称为“噩梦”的文件系统“不是熊跳得有多好,而是熊跳得有多好”。令人惊讶,但它根本就跳舞”。
1991 年的 NFS2 慢慢地从 Sun 爬出到其他平台,并且相对粗糙。安全模型本质上是不存在的(客户端计算机上的 root 可以读取 NFS 安装的完整内容),而锁定(通过 nfs.lockd)是实验的这一面。如果在两个不同的据称可互操作的实现之间期望集群语义能够正常工作,那么您将是愚蠢的。同轴电缆是当时占主导地位的以太网 PHY,许多网络用户从未有过使用的不愉快(你的意思是你忘了把 50
答案2
现在这个已经过时了。 NFS4 支持锁定协议内(不需要 lockd 守护进程或 RPC 回调机制)并且 Perl 的flock()
方法工作正常 - 我们在生产中使用它。
非常旧的内核版本flock
(系统调用)在 NFS 上作为无操作实现,并且未正确支持字节范围锁定等其他内容。这就是歇斯底里的根源。
答案3
Lennart Poettering 最近对 Linux 文件系统锁定行为进行了一些深入研究,这并没有为 NFS 锁定描绘出一幅特别美好的图景(尤其是他在帖子底部链接到的后续内容)。
答案4
另一篇,直接来自 Linux-NFS FAQ:nfs.sf.net
我正在尝试使用集群()/BSD 锁来锁定多个客户端上使用的文件,但文件已损坏。怎么会?答:flock()/BSD 锁仅在 2.6.12 之前的 Linux NFS 客户端上本地起作用。使用 fcntl()/POSIX 锁来确保文件锁对其他客户端可见。
以下是序列化对 NFS 文件的访问的一些方法。
使用 fcntl()/POSIX 锁定 API。这种类型的锁定通过 NLM 协议或 NFSv4 跨多个客户端提供字节范围锁定。使用单独的锁定文件,并创建指向它的硬链接。请参阅 creat(2) 手册页的 O_EXCL 部分中的描述。值得注意的是,直到早期的 2.6 内核,O_EXCL 创建在 Linux NFS 客户端上都不是原子的。不要使用 O_EXCL 在多个 NFS 客户端之间创建并期望原子行为,除非您运行的内核高于 2.6.5。
Perl 默认情况下使用集群()/BSD 锁定是一个已知问题。这可能会破坏从其他操作系统(例如 Solaris)移植的程序,这些操作系统期望集群/BSD 锁像 POSIX 锁一样工作。
在 Linux 上,使用文件锁定而不是硬链接具有在服务器与客户端缓存之间建立检查点的额外好处。当获取文件锁时,客户端将刷新该文件的页面缓存,以便任何后续读取从服务器获取新数据。释放文件锁时,该客户端上对该文件的任何更改都会在释放锁之前刷新回服务器,以便等待锁定该文件的其他客户端可以看到这些更改。
2.6.12 中的 NFS 客户端通过根据 POSIX 字节范围锁模拟 BSD 样式锁,为 NFS 文件上的集群()/BSD 锁提供支持。使用相同模拟机制或使用 fcntl()/POSIX 锁的其他 NFS 客户端将看到与 Linux NFS 客户端看到的相同锁。
在本地 Linux 文件系统上,POSIX 锁和 BSD 锁彼此不可见。因此,由于这种模拟,在 Linux NFS 服务器上运行的应用程序仍然会将 NFS 客户端锁定的文件视为使用 fcntl()/POSIX 锁锁定,无论客户端上的应用程序使用的是 BSD 样式还是 POSIX-风格锁。如果服务器应用程序使用flock()BSD锁,它将看不到NFS客户端使用的锁。