根本原因在于网络抖动与远程存储协议协同作用:短暂丢包或延迟尖峰会触发客户端重传、服务端超时、内核缓存失效,甚至挂载点soft lockup;排查需将网络抖动和i/o阻塞在时间轴上对齐,而非孤立分析。

分布式文件系统(如 NFS、CephFS、GlusterFS)的 I/O 挂起,往往不是单纯的“磁盘慢”或“网络断”,而是网络抖动与远程存储协议协同作用的结果:一次短暂的丢包或延迟尖峰,可能触发客户端重传、服务器端连接超时、内核缓存失效、甚至挂载点进入“soft lockup”状态。排查这类问题,关键在于把“网络链路抖动”和“I/O 调用阻塞”在时间轴上对齐,而不是分开查。
先确认挂起是否真由网络抖动引发
别一上来就抓包。先做三件事快速过滤:
- 执行 mount | grep -E "(nfs|ceph|gluster)",看挂载选项里是否有 soft(软挂载)。如果是,I/O 会因超时直接报错返回(如 Connection timed out);但如果是 hard,intr(硬挂载可中断),挂起更常见,也更难排查。
- 运行 cat /proc/mounts | grep your-mount,检查 timeout= 和 retrans= 值。默认 timeout 多为 60 秒,retrans 为 3 —— 这意味着客户端最多等近 3 分钟才放弃,期间进程就卡在 D 状态(不可中断睡眠)。
- 用 ps aux | awk '$8 ~ /^D$/ {print}' 找出所有 D 状态进程,再结合 lsof -p PID 确认它们是否都在访问该挂载点路径。如果大量进程卡在同一个目录下读写,基本锁定是挂载层问题。
定位抖动发生的时间窗口与对应网络行为
网络抖动本身不报警,但它的后果会在多个层面留下痕迹。你需要同步采集三类日志:
- 客户端内核日志:运行 dmesg -T | grep -i "nfs\|rpc\|timeout\|server",重点找类似 "NFS: server xxx not responding, still trying" 或 "RPC: failed to send" 的记录,记下精确时间戳。
- 网络层指标:在抖动疑似时段,用 ping -c 60 -i 0.1 target-nfs-server 记录 RTT 分布;再用 mtr --report --interval 1 --count 60 target-nfs-server 查中间跳点丢包。注意:不要只看平均延迟,要看 RTT 方差(rttvar) 和 最大延迟突刺 —— 比如平时 2ms,突然跳到 800ms,就是典型抖动。
- NFS 客户端统计:执行 nfsstat -c(客户端统计),重点关注 retrans(重传次数)和 timeouts(超时数)列。若这两项在挂起前后陡增,说明网络已影响协议层。
验证是否为协议栈级阻塞而非应用层卡死
很多场景下,进程看似“挂起”,实则是应用自己没设超时、循环重试导致的假象。要区分清楚:
- 用 strace -p PID -e trace=connect,sendto,recvfrom,read,write 跟踪一个卡住的进程。如果看到反复 recvfrom() = -1 EAGAIN 或长时间停在 read() 不返回,说明是内核 NFS 客户端在等响应;如果看到 read() 后立刻又调用 read(),可能是应用逻辑问题。
- 检查 /proc/sys/sunrpc/ 下的关键参数:
• tcp_fin_timeout(默认 60)太小会导致连接频繁重建;
• timeo(NFS 重传初始超时,单位 1/10 秒)设得太短(如 3 即 300ms)会让轻微抖动直接触发重传;
• retrans(重传次数)过高会拉长整体等待时间。这些值可在挂载时通过 timeo=600,retrans=2 调整。
检查服务端与中间链路是否存在隐性瓶颈
客户端看到的是“连不上”,但根因可能在远端:
- 登录 NFS 服务端,运行 rpcinfo -p localhost 确认 nfsd、mountd 是否正常注册;再用 ss -tnp | grep :2049 看端口监听和 ESTAB 连接数是否异常堆积。
- 检查服务端磁盘 IO:如果服务端自身 %wa 高或 iostat -x 1 显示 await > 50ms,那么客户端的“网络抖动”其实是服务端 IO 慢导致响应延迟,被 NFS 协议误判为网络问题。
- 排查中间设备:特别是虚拟化环境中的 vSwitch、SDN 控制器或物理交换机的 buffer 溢出。用 ethtool -S eth0 | grep -i "drop\|error" 查收发丢包计数;若有明显增长,说明链路层已开始丢帧,比 TCP 层抖动更底层。











