磁盘队列深度过高本质是I/O请求在内核层积压,导致进程大量处于D状态、响应迟缓甚至假死;需先用iostat -x 1确认avgqu-sz是否超标(HDD>2、SATA SSD>8、NVMe>32且await同步飙升),再用iotop/pidstat定位高IO进程,最后检查设备队列、调度器及挂载参数等底层限制。

磁盘队列深度过高,本质是 I/O 请求在内核层积压,进程大量处于不可中断睡眠(D 状态),系统看似“CPU 低、内存足”,却响应迟缓甚至假死。这不是磁盘坏了,而是请求发得太快、设备处理不过来。排查核心思路是:先确认队列是否真高,再定位谁在塞队列,最后看是不是配置或硬件拖了后腿。
看 avgqu-sz 是否持续超标
iostat -x 1 是第一把尺子。重点关注 avgqu-sz(平均队列长度)这一列:
- 机械盘(HDD):avgqu-sz > 2 就值得警惕,> 4 通常已明显卡顿;
- 普通 SATA SSD:avgqu-sz > 8 表示压力较大,> 16 往往伴随高 await 和业务延迟;
- 高性能 NVMe 盘:单队列深度可达 64+,但若 avgqu-sz 长期 > 32,且 %util 未到 90%,说明上层应用并发远超磁盘实际吞吐能力。
同时对照 await(平均等待毫秒数):如果 avgqu-sz 高但 await 仅几毫秒,可能是短时突发;若 avgqu-sz 和 await 同步飙升(比如 await > 100ms),基本可断定是真实瓶颈。
找正在填满队列的进程
iotop 和 pidstat -d 是两个互补工具:
- iotop -o:只显示当前有 I/O 活动的进程,按 IO_RATE 排序,一眼看出谁在狂写/狂读;
- pidstat -d 1:输出更稳定,带 kB_rd/s 和 kB_wr/s,还能看到 pgpgin/pgpgout(页换入换出量),辅助判断是否因内存压力间接引发大量 swap I/O;
- 注意区分“真 IO 进程”和“被阻塞进程”:top 中状态为 D 的进程不消耗 CPU,但会持续占用队列槽位,它们本身不是源头,而是受害者——要顺着它查父进程或触发它的服务(比如某个数据库查询导致日志刷盘阻塞)。
查队列背后的底层限制
队列深度不是无限的,受三方面硬约束:
- 设备队列深度:cat /sys/block/sda/queue/nr_requests 查默认队列大小(常见值为 128 或 256);
- I/O 调度器策略:用 cat /sys/block/sda/queue/scheduler 查当前调度器。CFQ(旧版)易堆积,deadline 对低延迟友好,noop 或 mq-deadline 更适合 SSD/NVMe;
- 挂载参数影响:如 ext4 文件系统若用了 data=journal 模式,每次写都要先写日志,双倍 IO 放大;检查 mount 输出中是否有 barrier=1、commit=5 等加重同步负担的选项。
验证是否 NUMA 或多路径干扰
在多 CPU 插槽服务器或使用多路径存储(如 DM-Multipath)时,队列可能局部过载:
- 运行 numastat,看进程是否跨 NUMA 节点频繁访问远端内存,导致 I/O 路径变长、响应时间拉高;
- 执行 lsblk -t,确认 sda 是否由多个路径聚合而成;若 multipath -ll 显示 active/passive 状态不均,部分路径失效会导致剩余路径队列瞬间打满;
- 对比 iostat -x 1 中各路径设备(如 mpatha、sdb、sdc)的 avgqu-sz,不均衡即为线索。


















