多个附加程序写入 NFS 共享上的同一文件

Fid*_*del 4 io-redirection nfs concurrency files

如果我有 100 台服务器执行一个命令,并且每台服务器都将它们的输出重定向到 NFS 共享上的同一个文件,那么生成的文件会整齐地交错还是会损坏?

例如,如果此命令在 100 个服务器上执行:

find / type -f >> /some_server/share/file_list.txt
Run Code Online (Sandbox Code Playgroud)

会不会腐败?

附:该命令只是一个例子,我实际上并没有列出文件

ilk*_*chu 7

简而言之:是的,来自多个 NFS 客户端的同时写入将被破坏。

本地同时追加很好地交错,因为操作系统知道文件是以追加模式打开的,并且在每次写入调用之前自动寻找文件的当前结尾,而不管其他进程可能同时扩展了文件。

但是在 NFS 上,没有这样的运气。在Linux的NFS常见问题解答声明说白了:

A9. 为什么在多个客户端上使用 O_APPEND 打开文件会导致文件损坏?
A. NFS 协议不支持原子追加写入,因此追加写入在 NFS 上对于任何平台都不是原子的。
大多数 NFS 客户端,包括内核高于 2.4.20 的 Linux NFS 客户端,都支持“close to open”缓存一致性,

A8. 什么是近开缓存一致性?
A. 在不同的 NFS 客户端之间实现完美的缓存一致性是非常昂贵的,因此 NFS 满足于满足大多数日常文件共享类型要求的较弱的东西。[...]

当应用程序关闭文件时,NFS 客户端会将所有挂起的更改写回文件,以便下一个打开程序可以查看更改。这也使 NFS 客户端有机会通过 close() 的返回码向应用程序报告任何服务器写入错误。这种行为被称为接近开放的缓存一致性。

NFS写操作只包含要写入的位置和要写入的数据。没有规定集中协调文件末尾的位置,这是确保客户端不会相互覆盖所需要的。

(该页面看起来确实有点旧,因为它主要讨论 Linux 内核版本 2.6,没有提及 3.x。但是提到 NFS 版本 4 与内核支持有关,因此可以假设答案也适用于 v4 .)


在最近的 Linux 和 NFS v3 共享上进行的小测试:

在 shell 循环 ( for ((i=0 ; i<9999 ; i++)) ; do printf "$id %06d\n" $i >> testfile ; done) 中同时在两个客户端上写出数字会导致输出损坏。一部分:

barbar 001031
foo 000010
32
foo 000011
33
foo 000012
Run Code Online (Sandbox Code Playgroud)

在这里,一台机器上的第一个循环用 写了行barbar,而另一台机器上的另一个循环写了这些foo行。应该说的行barbar 001032从与foo 000010行相同的位置开始写入,只有较长行的最后数字可见。(请注意,在这种情况下,printf由于重定向在循环内,因此文件实际上是为每个文件打开和关闭的。但它仅有助于查找文件打开时文件的结尾。)

如果文件始终保持打开状态,则可能会覆盖更大的块,因为只有在文件关闭时客户端系统才会将更改写入服务器。即使在打开时截断文件也不会改变这么多,因为截断只会清除文件,但不会阻止其他客户端在关闭文件时进一步写入。