iostat -x 1输出中真正有用的是r_await、w_await(含排队与服务时间,hdd>10ms/sata ssd>1ms即预警)、aqu-sz(平均队列长度,持续>1表明排队)、%util对nvme等多队列设备失效,svctm已被废弃。

直接看 iostat -x 1,别先跑 top 或查日志——磁盘 I/O 瓶颈不会藏在 CPU 或内存里,它就明晃晃写在设备队列和延迟里。
iostat -x 输出里哪些字段真有用?
新版 iostat(Linux 5.0+)的 -x 模式才值得盯住,老式 %util 在 NVMe 上基本失效:
-
r_await和w_await:请求从进队列到完成的平均耗时(ms),含等待 + 服务时间。HDD 超 10ms、SATA SSD 超 1ms 就该警觉 -
aqu-sz:当前平均队列长度。持续 >1 表示 I/O 在排队,不是设备慢,是压得太狠 -
svctm已被内核废弃,别信它;%util对多队列设备(如 NVMe)只反映单个队列忙时,实际负载可能远高于显示值 -
rrqm/s和wrqm/s高,说明上层发了大量小请求,可合并但没合并——常见于未对齐的 4K 写或日志刷盘策略不当
iotop 只显示“谁在读写”,但容易误判
iotop 是定位进程的第一步,但默认输出有陷阱:
Zynq‑7000 / Zynq UltraScale+ 硬件调试技能。适用于 Xilinx Zynq(Cortex‑A9/A53 + FPGA)Linux 环境,调试 I2C、I2S、UART、GPIO 等外设。包括设备树配置、内核驱动、用户空间调试工具、交叉编译和常见问题排查,支持 PetaLinux 开发。
- 不加
-o会混入大量休眠线程,真正干活的进程被淹没 - 显示的
IO>百分比是相对所有 I/O 的占比,不是绝对带宽;KB/s列才是真实吞吐,优先看它 - 若看到
java或mysqld占高,别急着杀进程——先用lsof -p PID确认它读的是哪个文件,再结合cat /proc/PID/io看rchar/wchar(系统调用层字节数)和read_bytes/write_bytes(实际落盘字节数)差多少,判断是否卡在 Page Cache
/proc/diskstats 是唯一可信的原始计数器
所有工具(包括 iostat)最终都读它,但字段含义常被误解:
- 第 4 列(读完成次数)和第 8 列(写完成次数)是真实完成的 I/O 次数,不受合并影响
- 第 6 列(读扇区数)和第 10 列(写扇区数)单位是 512 字节扇区,不是字节;换算成 KB 要 ×512÷1024 = ×0.5
- 第 13 列(I/O 进行中的时间,单位 ms)是累计值,除以采样间隔才能得近似并发请求数;它比
aqu-sz更底层,也更难解读 - 直接
watch -n1 'cat /proc/diskstats | grep nvme0n1'看数字跳变,比任何工具都快——尤其当你怀疑监控工具自身在刷盘时
dd 测试只能测极限,不能反映真实负载
用 dd if=/dev/zero of=test bs=1M count=1024 oflag=direct 测出 2GB/s,不代表数据库就快:
-
dd是单流、大块、顺序写,绕过缓存,测的是裸设备吞吐上限 - 真实业务多是随机小 IO(如 MySQL 的 16KB page)、混合读写、带元数据操作,
dd完全不模拟这些 - 若非要测,至少加
conv=fdatasync强制刷盘,否则结果全是缓存速度;但更推荐用fio配置rw=randread,bs=4k,iodepth=32模拟 OLTP 场景
最常被忽略的一点:I/O 延迟不是恒定值,r_await 是平均值,而 P99 延迟可能高出 10 倍——如果应用卡顿是偶发的,光看平均值会漏掉问题。这时候得上 blktrace 抓原始事件,或者用 perf record -e block:block_rq_issue,block:block_rq_complete 做轻量级采样。










