iostat -x 1 是唯一能抓到真实 iops 实时峰值的方式,因其 r_ios 和 w_ios 字段反映内核块层实际下发到设备的每秒请求数,而 dstat、vmstat 及不带 -x 的 iostat 输出的是 vfs 层合并后的逻辑请求数,常虚高 2–5 倍。

iostat -x 1 是唯一能抓到真实 IOPS 实时峰值的方式
别信 dstat、vmstat 或不带 -x 的 iostat —— 它们输出的 r/s 和 w/s 是 VFS 层合并后的逻辑请求数,受 page cache、请求重排、virtio-blk 协议头或 NVMe 多队列干扰,数值常虚高 2–5 倍。只有 iostat -x 1 输出的 r_ios 和 w_ios 字段,才是内核块层实际下发到设备或 virtio queue 的每秒请求数,即真实 IOPS。
-
iostat -dx 1:每秒刷新,跳过首行冷启动噪音(首行是平均值,不准) -
iostat -xh 1:自动换算单位(K/M/G),但字段名仍叫rMB/s,读起来更直观 -
iostat -xk 1:固定 KB 单位,数值精确,适合脚本解析(注意字段名仍是rMB/s,历史兼容) - 只看某盘?加路径:
iostat -xh 1 /dev/nvme0n1 - 要看所有分区(含 LVM、RAID 子卷)?用
iostat -xh 1 -p ALL
为什么 %util 不能当 IOPS 峰值用
%util 接近 100% ≠ IOPS 到顶了。它只是设备忙时占比,对 SSD/NVMe 几乎无参考价值:一块 PCIe 4.0 NVMe 盘在 %util=60% 时,w_ios 就可能已卡在队列深度上限,await 暴涨到 20ms+;而一块 HDD 在 %util=95% 时,r_ios 可能才 80,远未达物理极限。
- 真正反映瓶颈的是
await+avgqu-sz:await > 10ms且avgqu-sz > 1(SSD)或> 2(HDD),说明请求已在队列积压 -
%util高但await低 → 设备响应快,只是持续干活(比如大块顺序写) -
%util低但await高 → 单个请求慢(如小块随机读、RAID 卡 flush 延迟、文件系统锁争用)
实时峰值容易被误读的三个坑
iostat -x 1 每秒打点,但“峰值”不是看单次最大值——真实业务压力下 IOPS 是脉冲式爆发,一秒内可能有几十次尖峰,iostat 只取整秒统计,会平滑掉瞬时毛刺。要捕获这种峰值,必须配合其他手段。
- 别只盯终端输出:用
iostat -dx 1 > iostat.log 2>&1 &后台记录 60 秒,再用awk '{print $3}' iostat.log | sort -n | tail -1提取r_ios最大值 -
r_ios和w_ios是分开统计的,混合负载下总 IOPS =r_ios + w_ios,但不能简单相加后和厂商标称比——SSD 标称 500K IOPS 通常指纯读或纯写,混合场景必然下降 - 云环境(KVM/virtio)下
r_ios是 guest kernel 下发到 virtio queue 的次数,不等于物理 SSD 的 NAND 操作数;宿主机侧需用perf或virtiostat观测真实落盘行为
定位谁在刷出 IOPS 峰值
iostat -x 告诉你“设备忙”,但从不告诉你“谁干的”。当 r_ios 或 w_ios 突然拉高,得立刻查进程源。
- 实时锁定高 IO 进程:
sudo iotop -oP(-o只显示实际在做 IO 的进程,-P忽略线程) - 按秒采样并导出:
pidstat -d 1,关注rkB/s和wkB/s,换算 IOPS 要除以平均 IO 大小(如 PostgreSQL 默认 8KB → ÷8) -
iotop显示的DISK WRITE不等于iostat的w_ios:前者含 write-back 缓存未落盘数据,后者是真正发往设备的请求数;差值大说明缓存堆积,w_ios还没爆发,但马上就要来了
r_ios/w_ios 的脉冲里,而不是 %util 的平稳高位上;盯错字段,排查方向就全偏了。











