在 NFS 挂载上(RedHat 5.6 上的标准选项和古老的 2.6.18 内核),在我看来,大而多的写入操作会延迟较小的读取操作。例如,ls
如果有cp
或dd
并发运行,则在目录中执行简单操作将需要几秒钟(或几分钟)。这个问题有所缓解,因为 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
那个慢(提交时需要几个我们),而是内核在所有WRITE
s之后将它排队。
这就是为什么stat
需要很长时间,因为它等待内核提交GETATTR
调用。
我对吗 ?这看起来像是一个缓冲区膨胀问题,内核正在饿死我,stat
因为此安装(服务器?)的客户端操作队列已满。
我认为这与我的另一个问题如何实现到同一台服务器的多个 NFS/TCP 连接有某种关系?.
有没有办法调整内核 NFS 操作队列?
好的,这是我的答案。
与 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
似乎与时间匹配dd
)WRITE
。写入越大,等待时间越长。
对于速度较慢的 NFS 服务器或具有大量 RAM 的服务器,延迟可能长达几分钟。当 stat(2)
进入睡眠状态时,人们可以监视/proc/meminfo
或NFS_Unstable
显示Writeback
有多少数据正在传输。
我不确定内核为什么这样做,但至少现在我理解了这种行为。因此不存在缓冲区膨胀,但某些操作是序列化的。
归档时间: |
|
查看次数: |
1538 次 |
最近记录: |