在NFS挂载(RedHat 5.6与古老的2.6.18内核的标准选项),在我看来,大和多写操作延迟较小的读取操作。 例如,如果同时运行cp或dd则在目录中执行简单的ls将花费数秒(或数分钟)。 由于Linux将元数据caching了几秒钟,这个问题有点缓解,但是当需要写入大量数据时,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开始时,下一个执行caching未命中的状态需要15s
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是asynchronous的,我期望看到GETATTR调用与WRITE多路复用,但事实并非如此。 这不是GETATTR的慢(提交时需要我们几个),它是在所有WRITE之后将其排队的内核。
这就是为什么stat需要很GETATTR ,因为它等待内核提交GETATTR调用。
我对吗 ? 这看起来像一个bufferbloat问题,内核饿死我的stat因为这个安装(服务器?)的客户端操作队列已满。
我认为这是以某种方式与我的其他问题有关如何实现多个NFS / TCP连接到同一台服务器? 。
有没有办法调整内核NFS操作系统队列?
好的,这是我的答案。
与RedHat提供的内核2.6.18和2.6.32相关的https://bugzilla.redhat.com/show_bug.cgi?id=688232 (我没有时间用vanilla新内核重新validation),on一个NFS客户端(v3 / tcp / default mount选项),当一个文件正在写入时,内核也需要更新这个文件的时间戳。 当文件正在被写入时,如果另一个进程需要这个文件的元数据(比如当对这个文件进行stat ,或者在其父目录下执行ls -l时),这个读取器进程被内核延迟,直到写入完成。
在NFS级别,我可以看到内核只会在所有的(我不确定在这个,但在我的testing高达5GiB, stat时间似乎匹配dd时间)发出GETATTR调用WRITE 。 写入越大,等待时间越长。
如果NFS服务器速度较慢,或者内存很大,那么延迟时间可能只有几分钟。 当stat(2)进入睡眠状态时,可以监视/proc/meminfo中的NFS_Unstable或NFS_Unstable ,它显示有多less数据正在飞行。
我不知道为什么内核会这样做,但至less现在我明白了这个行为。 所以没有bufferbloat,但有些操作是序列化的。