这个问题有点缓解,因为 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
并行的tcpdump告诉我以下内容:
1)每当dd开始时,执行缓存未命中的下一个统计信息需要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
2)tcpdump显示当dd正在运行并且发出WRITE调用时,不会发送单个GETATTR.
鉴于RPC是异步的,我本来希望看到GETATTR调用与WRITE多路复用,但事实并非如此.
GETATTR不是很慢(提交时需要几个我们),它是在所有WRITE之后排队的内核.
这就是为什么stat需要很长时间,因为它等待内核提交GETATTR调用.
我对吗 ?
这看起来像一个bufferbloat问题,内核正在挨饿我的stat,因为这个mount(服务器?)的客户端操作队列已满.
我认为这与我的其他问题How to achieve multiple NFS/TCP connections to the same server?有某种关系.
有没有办法调整内核NFS操作队列?
解决方法
与RedHat一起提供的内核2.6.18和2.6.32的https://bugzilla.redhat.com/show_bug.cgi?id=688232相关(我没有时间用vanilla更新的内核重新验证),在NFS客户端(v3 / tcp / default mount options)上,当一个是写入文件时,内核还需要更新该文件的时间戳.在写入文件时,如果另一个进程需要此文件的元数据(例如在此文件上执行stat或在其父目录中执行ls -l时),则此读取器进程会被内核延迟,直到写入完成.
在NFS级别,我可以看到内核只会发出GETATTR调用(我不确定这个,但在我的测试中最多5GiB,统计时间似乎与dd时间匹配)WRITE.写入越大,等待的时间越长.
使用慢速NFS服务器或具有大量RAM的服务器,该延迟可能是几分钟.当stat(2)进入休眠状态时,可以监视/ proc / meminfo以查找NFS_Unstable或Writeback,它显示有多少数据是飞行的.
我不确定为什么内核会这样做,但至少现在我理解了这种行为.所以没有bufferbloat,但有些操作是序列化的.