我有一个 Debian squeeze (2.6.32-5-amd64),它同时是一个 NFS4 服务器和客户端(它通过 NFS4 自行安装)。直接指向磁盘的本地目录是/nfs4exports/mydir
,而/nfs4mounts/mydir
同样是通过 NFS 安装的东西,使用机器的外部 IP 地址。这是来自的行fstab
:
192.168.1.75:/mydir /nfs4mounts/mydir nfs4 soft 0 0
我有一个写入许多小文件的应用程序。如果我直接/nfs4exports/mydir
写入,它每秒写入数千个文件;但如果我写入/nfs4mounts/mydir
,它每秒写入 4 个文件左右。我可以大大提高速度,如果我添加async
到/etc/exports
. (将单个大文件写入 NFS 挂载目录的速度超过 100 MB/s。)
我检查了服务器统计数据,发现无论何时写入文件,它都是“已提交”的(NFSv3 也会发生这种情况):
root@debianvboxtest:~# mount -t nfs4 192.168.1.75:/mydir /mnt
root@debianvboxtest:~# nfsstat|grep -A 2 'nfs v4 operations'
Server nfs v4 operations:
op0-unused op1-unused op2-future access close commit
0 0% 0 0% 0 0% 10 4% 1 0% 1 0%
root@debianvboxtest:~# echo 'hello' >/mnt/test1056
root@debianvboxtest:~# nfsstat|grep -A 2 'nfs v4 operations'
Server nfs v4 operations:
op0-unused op1-unused op2-future access close commit
0 0% 0 0% 0 0% 11 4% 2 0% 2 0%
现在在RFC中,我读到这个:
COMMIT 操作在操作和语义上类似于将文件状态与磁盘同步的 POSIX fsync(2) 系统调用(文件数据和元数据刷新到磁盘或稳定存储)。COMMIT 对客户端执行相同的操作,将服务器上任何未同步的数据和元数据刷新到服务器的磁盘或指定文件的稳定存储中。
我不明白客户为什么要承诺。我认为“echo”shell 内置命令不会运行fsync
;如果echo
写入本地文件然后机器宕机,文件可能会丢失。相反,NFS 客户端似乎在完成echo
. 为什么?
我不愿意使用async
NFS 服务器选项,因为它显然会忽略 COMMIT。我觉得我好像有一个本地文件系统,我不得不在关闭时同步每个文件和fsync
完全忽略之间做出选择。我理解错了什么?
因为这就是 NFS 的工作方式,而且正是它应该如何工作,因为它是一个同步协议。您需要确保导出的文件系统由具有 NVRAM/BBWC 保护并正确处理 fsync() 的 LUN 支持——即忽略它,并屏蔽 SCSI FUA 标志和 SCSI_CACHE_SYNCHRONIZE 命令。如果文件系统受 BBWC/NVRAM 支持,还要确保文件系统没有启用障碍。
这样,NFS 保持同步语义,相当于在每次写入后运行 fsync(),但您可以获得异步运行的性能。