r高但id高说明存在“假性CPU空闲”:大量进程卡在不可中断睡眠(D状态),堆满运行队列却不消耗CPU,也不计入iowait。

vmstat 中 r 高但 id 也高,说明什么?
这恰恰是典型“假性 CPU 空闲”陷阱:r(运行队列中进程数)持续 > CPU 核数,而 id(空闲 CPU)却很高(比如 >70%),wa(iowait)却不显眼——表面看 CPU 没事,实际系统已卡在 IO 路径上。根本原因不是 CPU 忙,而是大量进程卡在不可中断睡眠(D 状态),它们不消耗 CPU,也不进入 iowait(因为 iowait 只统计“CPU 空闲且等 IO”),但会堆满运行队列并拖慢响应。
为什么 pidstat -d 和 ps aux | grep " D " 必须一起用?
pidstat -d 1 能看到谁在狂写(如 WRITE_KB >50MB/s)、谁的 %io 超 30%,但它无法告诉你线程是否已卡死;而 ps aux | grep " D " 找出的是真正卡在内核 IO 路径里的进程(状态为 D)。两者结合才能确认:是应用主动刷盘(可优化),还是底层被 block 住了(如 multipath 切路径、NVMe 队列溢出、ext4 journal 锁争用)。
- 只看
pidstat可能误判:某个进程 IO 量不大,但它的多个线程全卡在D,导致服务无响应 - 只看
ps又难定位源头:D进程可能是数据库子进程,但真正触发它的是一条慢 SQL 或 fsync 调用 - 实操建议:先
ps aux | grep " D "抓 PID,再lsof -p查它正操作哪个文件或设备(如PID/dev/nvme0n1p2或容器 overlay2 卷)
iostat -x 1 里哪些字段暴露“伪低 util + 高延迟”陷阱?
当 %util 很低(比如 15%),但 w_await >50ms、avgqu-sz >2,就说明磁盘本身没饱和,但 IO 请求在内核层被拦住了——常见于驱动 bug、队列深度配置过小、或文件系统锁(如 XFS log stall)。这时 svctm 已弃用,但 w_await - r_await 的差值大,且 avgqu-sz 持续 >1,就是排队发生在 queue 之前(bio 层或 request 层)的信号。
-
await高 +%util低 → 不是磁盘慢,是下发路径堵了 -
rrqm/s或wrqm/s高 → 合并请求频繁,可能 I/O 模式极碎(如大量 4KB 随机写) - 配合
cat /proc/diskstats对比ios_pgr(in flight IO 数)和io_ticks,能验证是否真有 IO 卡在 driver 层
安卓或容器环境里,vmstat 的 b 字段比 r 更值得盯
在受限环境(如 Android、Kubernetes Pod),r 可能被 cgroup 限频扭曲,而 b(等待 IO 的进程数)更真实反映阻塞压力。尤其当 b 持续 >0 且 bi/bo 波动剧烈时,基本可断定是底层存储(如 eMMC、UFS 或网络盘)响应不稳,而非应用问题。
- 安卓调试必加:
adb shell vmstat 1看b,再adb shell iostat -d -x 1看具体设备(如sda或mmcblk0)的%util和await - 容器中
b高但宿主机wa低?说明 IO 被 cgroup blkio 限速或 throttled,查/sys/fs/cgroup/blkio/.../blkio.io_service_bytes - 别迷信
wa:虚拟化中st(steal time)高时,wa可能被压缩失真
真正卡住系统的,往往不是慢盘,而是那一两个卡在 D 状态、没人敢杀、又拒绝超时的线程——它们不占 CPU,不刷日志,只悄悄把整个服务拖进深渊。









