这是 Linux NFS 客户端缓冲区膨胀吗?

Ben*_*oît 5 linux nfs

在 NFS 挂载上(RedHat 5.6 上的标准选项和古老的 2.6.18 内核),在我看来,大而多的写入操作会延迟较小的读取操作。例如,ls如果有cpdd并发运行,则在目录中执行简单操作将需要几秒钟(或几分钟)。这个问题有所缓解,因为 Linux 将元数据缓存了几秒钟,但是当有大量数据要写入时,NFS 挂载变得不可用。

起初我认为这只是一个 NFS 服务器问题,但运行如下:

for((i=0; i<60; i++)) do
  strace -f -t -o strace.$i.log time stat /mnt/nfs/data > out.$i.log 2>&1
  sleep 1
  if ((i == 30)); then
    dd if=/dev/zero of=/mnt/nfs/data bs=1M count=1000 &
  fi
done

wait
Run Code Online (Sandbox Code Playgroud)

并行的 tcpdump 告诉我以下内容:

1) 每当dd开始时,下stat一个缓存未命中需要 15 秒

23261 16:41:24 munmap(0x2ad024d0e000, 4096) = 0
23261 16:41:24 lstat("/mnt/fermat_emctest/data", {st_mode=S_IFREG|0600, st_size=1048576000, ...}) = 0
23261 16:41:40 open("/proc/filesystems", O_RDONLY) = 3
Run Code Online (Sandbox Code Playgroud)

2) tcpdump 显示在dd运行和WRITE发出调用时,没有GETATTR发送一个。鉴于 RPC 是异步的,我本希望看到GETATTR与 多路复用的调用WRITE,但事实并非如此。不是GETATTR那个慢(提交时需要几个我们),而是内核在所有WRITEs之后将它排队。

这就是为什么stat需要很长时间,因为它等待内核提交GETATTR调用。

我对吗 ?这看起来像是一个缓冲区膨胀问题,内核正在饿死我,stat因为此安装(服务器?)的客户端操作队列已满。

我认为这与我的另一个问题如何实现到同一台服务器的多个 NFS/TCP 连接有某种关系.

有没有办法调整内核 NFS 操作队列?

Ben*_*oît 2

好的,这是我的答案。

与 RedHat 附带的带有内核 2.6.18 和 2.6.32 的https://bugzilla.redhat.com/show_bug.cgi?id=688232相关(我没有时间用普通的较新内核重新验证这一点),一个 NFS 客户端(v3/tcp/默认挂载选项),当写入文件时,内核还需要更新该文件的时间戳。在写入文件时,如果另一个进程想要该文件的元数据(例如stat在该文件或ls -l其父目录中执行 a 操作时),则该读取进程会被内核延迟,直到写入完成。

在 NFS 级别,我可以看到内核GETATTR最终只会发出调用(我对此不确定,但在我高达 5GiB 的测试中,时间stat似乎与时间匹配ddWRITE。写入越大,等待时间越长。

对于速度较慢的 NFS 服务器或具有大量 RAM 的服务器,延迟可能长达几分钟。当 stat(2)进入睡眠状态时,人们可以监视/proc/meminfoNFS_Unstable显示Writeback有多少数据正在传输。

我不确定内核为什么这样做,但至少现在我理解了这种行为。因此不存在缓冲区膨胀,但某些操作是序列化的。