runq-sz 持续偏高但 %idle 很高,说明进程卡在不可中断睡眠(D 状态)而非 CPU 瓶颈,常见于 I/O 阻塞、内存回收或驱动异常;需用 ps、iostat、dmesg 等交叉定位。

runq-sz 显示的是当前就绪队列中等待被调度执行的进程数(包括正在运行和已就绪但未获得 CPU 的进程)。当 sar -q 输出中 runq-sz 持续偏高(比如 > 10,或明显超过 CPU 核心数),但 sar -u 显示 %idle 很高、%usr/%sys 很低时,说明系统有大量任务在排队,却没怎么用 CPU —— 这通常不是 CPU 真的空闲,而是这些任务被卡在了其他资源上,无法推进。
常见原因:I/O 等待被“隐藏”了
Linux 中,处于不可中断睡眠状态(D 状态)的进程不会计入 CPU 使用率(因为没跑在 CPU 上),但会留在 run queue 中,持续推高 runq-sz。这类进程往往卡在底层 I/O 操作上,例如:
- 等待慢速磁盘响应(如故障硬盘、RAID 同步、ext4 journal 阻塞)
- 访问挂载失败或响应极慢的 NFS/CIFS 共享
- 内核模块 bug 或驱动 hang 住(如某些旧版 NVMe 或 USB 存储驱动)
- 内存严重不足触发 direct reclaim,而回收过程又阻塞在 I/O(如 swapout 到慢盘)
快速定位 D 状态进程
直接查看当前有哪些进程卡在不可中断状态:
-
ps -eo pid,ppid,stat,comm,wchan --sort=-stat | head -20—— 关注 STAT 列含 D 的行,wchan 显示其等待的内核函数(如io_schedule、nvme_queue_rq、__wait_on_bit) -
ps aux | awk '$8 ~ /D/ {print $0}'—— 简单筛选 D 状态进程 -
cat /proc/[pid]/stack(对任一 D 进程)—— 查看其内核调用栈,确认阻塞点
结合 I/O 和内存指标交叉验证
单独看 runq-sz 容易误判,需同步检查:
-
sar -d 1 5:看 await、%util 是否异常高(尤其某设备 util 接近 100% 且 await > 100ms) -
iostat -x 1 5:关注 r_await/w_await、avgqu-sz(设备级队列长度),若 avgqu-sz 大但 %util 不高,可能是驱动或队列深度问题 -
free -h+cat /proc/meminfo | grep -E "^(MemAvailable|SwapFree|SReclaimable)":确认是否内存紧张导致频繁 kswapd 或 direct reclaim -
dmesg -T | tail -50:查找 I/O timeout、ATA/NVMe reset、NFS stale handle 等错误日志
典型场景示例
一台 8 核服务器,sar -q 显示 runq-sz 长期在 30–50,sar -u 显示 %idle > 95%,但用户反馈应用响应慢。执行 ps 发现 20+ 进程 STAT=D,wchan=“nvme_queue_rq”。进一步 iostat -x 显示 nvme0n1 的 await 达 2000ms,%util=99.8%,dmesg 有 “nvme 0000:01:00.0: Device not ready” 报错 —— 基本可判定是 NVMe 盘硬件故障或固件异常,导致所有发往该盘的 I/O 请求挂起,进程集体卡 D 状态,堆积在 run queue 中。








