ps查看stat列为d可快速判断进程是否卡在io,但d表示不可中断睡眠,未必是真io等待,需结合wchan、/proc/pid/io增量、dmesg和iostat交叉验证根因。

ps 怎么看进程是不是卡在 IO 上
直接看 STAT 列有没有 D —— 这是最快速的判断依据。但要注意:D 表示“不可中断睡眠”,不等于“正在做 IO”,而是“正在等内核完成某个不可打断的操作”,最常见的是磁盘或 NFS IO,但也可能是驱动卡死、RAID 卡超时、甚至某些加密模块阻塞。
推荐命令:
-
ps -eo pid,comm,state,wchan:20,WCHAN:30 --sort=-pcpu | grep ' D ':带wchan(等待的内核函数)能缩小根因范围; -
ps -eo pid,ppid,stat,etimes,cmd --sort=-etimes | head -15:etimes是进程上次被调度延迟的秒数,长期高值 +D状态基本可锁定为底层卡顿; - 别只用
ps aux | grep ' D ',它漏掉wchan和调度延迟,容易把假 D(如驱动 bug 产生的僵死等待)和真 IO 等待混为一谈。
iotop -o 为什么只显示部分 D 进程
iotop -o 默认只显示“当前有 IO 活动”的进程,包括正在读写、也包括刚进入等待但还没超时的 D 进程。但它**不会显示 read_bytes/write_bytes 长期不增长的 D 进程**——这类进程已经卡在驱动层或硬件响应上,内核没收到完成通知,IO 子系统根本没把它当“活跃”对待。
所以看到某进程是 D 但 iotop -o 不出现,不是工具失效,而是它已脱离 IO 调度路径。此时更该查:
-
cat /proc/<pid>/io</pid>中read_bytes和write_bytes是否静止不动; -
dmesg -T | tail -30是否有timeout、ata bus error、nfs: server not responding等线索; -
lsblk -S和smartctl -a /dev/sdX看设备是否已离线或 SMART 告警。
cat /proc/PID/io 的 read_bytes 和 write_bytes 为什么比实际小
read_bytes 和 write_bytes 统计的是**真正落到块设备上的字节数**,不包含 page cache 内存中的读写。比如你用 dd if=/dev/zero of=file bs=1M count=100,第一次运行时 write_bytes 会涨;但如果文件还在 cache 里、第二次再写同区域,write_bytes 可能完全不增加——因为内核只是标记脏页,还没刷盘。
这意味着:
- 一个进程
state=D且write_bytes静止,大概率不是应用没发写,而是块设备没响应; - 如果
read_bytes在涨但进程仍是D,说明它卡在后续处理(比如 NFS 解密、RAID 校验),不是磁盘本身慢; - 对比
rchar/wchar(用户态请求量)和read_bytes/write_bytes(实际落盘量),差值大说明 cache 效率高;差值为 0 且D持续,就是底层没动静了。
为什么 kill -9 对 D 进程无效
不是 kill 命令不好使,是内核根本没把信号投递给它。D 状态下进程控制权已交还给内核,正挂在某个不可中断的等待队列里(比如 __wait_event 或 wait_event_interruptible 的变体),连 SIGKILL 都无法唤醒——这是设计使然,防止数据损坏。
强行反复 kill -9 只会让进程状态从 D 变成 Z(僵尸),或者触发内核 panic(尤其在 RAID/NFS 场景)。真正要做的只有两件事:
- 查
wchan和/proc/<pid>/stack</pid>定位卡在哪一层(块设备?NFS?驱动?); - 针对根源动作:umount -f -l(NFS)、echo 1 > /sys/block/sdX/device/delete(热拔插故障盘)、重启 nfs-client 服务(非硬挂载场景);
- 切记:D 状态是症状,不是病灶;修复存储链路比“清理进程”重要得多。
最常被忽略的一点:D 进程是否真在等 IO,得靠 /proc/PID/io 的增量 + dmesg 日志 + iostat -x 的 await 三者交叉验证。单看 ps 的 D 或单看 iotop 的排序,都可能引向错误结论。











