发布时间:2026-09-24 04:30 更新时间:2026-09-24 04:30 阅读量:0
不少站长都遇到过这种反差场景:uptime 里的 load average 冲到几十甚至上百,但 top 里 CPU 使用率却不到 10%,机器表面看起来「闲着」,业务却明显变慢。这种情况在 Linux 上并不罕见,根因往往不在 CPU,而在处于 D 状态(不可中断睡眠)的进程。理解负载均值到底统计了什么,是把问题查清楚的第一步。
Linux 的 load average 统计的是运行队列长度,它包含三类任务:正在跑的(R 状态)、可以跑但等 CPU 的(R 状态排队)、以及处于不可中断睡眠的(D 状态)。第三类是很多人忽略的部分——D 状态进程通常在等待磁盘 I/O、NFS 响应或某些内核锁,这段时间它不占 CPU,却会实实在在把负载数字顶上去。所以「负载高 + CPU 空闲」几乎可以锁定方向:去查 D 状态进程。
顺带区分一个概念:iowait 表示 CPU 等待磁盘 I/O 完成的时间占比,它升高说明 I/O 变慢,但iowait 高不等于磁盘一定坏,也可能是文件系统、存储链路或网络存储的问题。而 D 状态进程是更直接的线索,它告诉你「谁在等」。
# 1) 看整体负载与运行队列
uptime
cat /proc/loadavg
2) 找出 D 状态进程(最常用的一步)
ps -eo pid,ppid,stat,wchan:32,comm | awk '$3 ~ /^D/'
3) 更直观地看状态位含义
ps -eo pid,stat,comm | grep -E ' D| R'
上面 ps 里 stat 字段的 D 就是不可中断睡眠。如果还带 l(小写 L)表示多线程,带 + 表示前台进程组,这些细节不影响主判断。wchan 列会显示进程卡在内核的哪个函数上,比如 nfs_ 开头的基本可以确认与 NFS 相关,以 io_schedule、blk_ 开头的多半是块设备 I/O 等待。
拿到 D 状态进程的 PID 和 wchan 之后,接下来要判断它到底在等哪一类资源。经验上可以按下面顺序推进:先看是不是本地磁盘慢,再看是不是 NFS 或网络文件系统卡住,最后考虑内核层面的锁竞争。
# 查看某进程的内核栈(需要 root,且内核开启了栈回溯)
cat /proc/<PID>/stack
看块设备 I/O 压力:%util 长期接近 100 说明设备饱和
iostat -x 2 5
看哪些进程在读写磁盘
iotop -o -d 2
查看挂载点类型,确认是否有 nfs / cifs
mount | grep -E 'nfs|cifs|fuse'
如果 iostat -x 里某块盘的 %util 长时间贴着 100、await 明显偏高,那 D 状态进程大概率在等这块盘。这时要结合业务判断:是备份/同步任务把盘打满了,还是磁盘本身接近寿命末期出现大量重试。若 mount 输出里有 nfs 或 cifs 挂载,而 wchan 又指向 NFS 相关函数,就要重点怀疑网络存储——NFS 服务端无响应时,客户端进程会长时间停在 D 状态,且 kill -9 也杀不掉,这是它的典型特征,不要反复尝试强杀,先恢复存储侧连通性。
排查 NFS 时可以先确认端口和 RPC 是否可达,再决定是重挂还是重启相关服务:
# 检查 NFS 服务端可达性与 RPC 状态
showmount -e <nfs_server>
rpcinfo -p <nfs_server>
查看内核 NFS 统计里的重传与超时
nfsstat -c
若确认存储已恢复但仍卡住,可在确认无写入的前提下强制卸载
umount -f /mnt/nfsdata
需要提醒的是,umount -f 属于比较激进的操作,执行前要确认挂载点上没有正在写入的关键业务,具体行为在不同内核版本上略有差异,以官方文档和实际环境为准。更稳妥的做法是先停掉引用该挂载点的服务,再卸载。
D 状态进程有一个容易踩的坑:处在不可中断睡眠中的进程通常无法被信号中断,kill -9 也无效。它只会在等待的事件完成(I/O 返回、NFS 恢复)后自行退出。所以看到一堆 D 状态进程时,反复 kill 没有意义,反而会掩盖现场。
另一个误区是「iowait 高就加内存或换 CPU」。iowait 反映的是等待比例,真正的瓶颈通常在存储层:机械盘随机读写、RAID 卡缓存策略、云盘 IOPS 上限、或者被其他进程抢占了带宽。排查时可以顺手看看是否有大批量任务在跑,比如备份、日志切割、镜像拉取,这些在业务高峰期运行很容易把负载推高。
日常缓解可以从这几方面入手:把重 I/O 任务挪到低峰时段并加限速;对 NFS 挂载使用合适的 soft/hard 与超时参数(注意 soft 可能带来数据一致性风险,需按业务取舍);对单盘热点考虑拆分或换用更高 IOPS 的存储。监控上建议同时采集 load、iowait、D 状态进程数和磁盘 await,单看负载数字很容易误判。
最后给一个排查顺序的小结:uptime 出现高负载 → ps 找 D 状态进程 → 看 wchan 判断等待类型 → iostat/nfsstat 定位存储侧 → 确认是本地盘、网络存储还是锁竞争 → 恢复资源或调整任务时机。按这条链路走,基本能绕开「CPU 明明空着却查不出原因」的困局。如果确认是磁盘硬件层面的持续异常,建议尽早做数据备份与设备更换评估,不要等到业务中断才处理。
| 📑 | 📅 |
|---|---|
| Redis 主从切换后写入报 READONLY:三种拓扑的误配排查 | 2026-09-23 |
| PostgreSQL表膨胀与autovacuum不生效排查实战 | 2026-09-23 |
| rsyslog 与 journald 双写日志重复或丢失排查 | 2026-09-23 |
| Linux conntrack 表满导致丢包:现场定位与容量评估 | 2026-09-23 |
| Nginx客户端与后端长连接谁在复用:端口耗尽排查顺序 | 2026-09-23 |
| Nginx 与 CDN 回源 IP 不一致:XFF 取值顺序与日志字段 | 2026-09-24 |
| Docker 容器内 Nginx 与宿主 Nginx 端口冲突排查 | 2026-09-24 |
| Nginx 443 端口 SNI 分流:WebSocket 与普通请求共用配置 | 2026-09-24 |
| MySQL 8 大事务致 undo 膨胀与主从延迟:定位与拆分提交 | 2026-09-24 |
| Docker 容器内 systemctl 不可用:init 缺失与多进程管理的取舍 | 2026-09-24 |