iostat —— 磁盘 I/O 性能分析
一句话定义
iostat 显示磁盘和 CPU 的 I/O 统计——每秒读写量、IOPS、平均延迟、利用率。是判断"磁盘是不是瓶颈"的标准工具。
典型场景
- 应用慢、想知道是不是磁盘瓶颈
- K8s 节点上 disk wait 高、找慢的盘
- 对比新旧盘 / 不同存储类型性能
- 持续监控生产负载
装
apt install -y sysstat # Ubuntu / Debian
yum install -y sysstat # CentOS / RHEL
sysstat 包含 iostat / mpstat / vmstat / sar 等。
1. 最常用一条
iostat -xz 1
| flag | 含义 |
|---|---|
-x | extended 详细模式(必加) |
-z | 跳过 0 活动的设备(输出更干净) |
1 | 间隔 1 秒持续刷 |
输出(逐字段解读):
Linux 5.15.0-91-generic (m4) 2026-05-27 _x86_64_ (4 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
5.00 0.00 2.00 8.00 0.00 85.00
^^^^
(1)
Device r/s w/s rkB/s wkB/s rrqm/s wrqm/s %rrqm %wrqm r_await w_await aqu-sz rareq-sz wareq-sz svctm %util
nvme0n1 50.0 200.0 3000.0 8000.0 2.0 50.0 3.85 20.0 0.50 2.00 0.45 60.0 40.0 0.04 80.0
^^ ^^^ ^^^^^^ ^^^^^^ ^^^ ^^^^ ^^^^^^ ^^^^^^^ ^^^^^ ^^^^
(2) (3) (4) (5) (6) (7) (8) (9) (10) (11)
| 标记 | 字段 | 含义 | 异常 |
|---|---|---|---|
| (1) | %iowait | CPU 等磁盘 I/O 时间占比 | > 20% 持续 = 磁盘是瓶颈 |
| (2) | r/s | 每秒读 I/O 数(IOPS) | - |
| (3) | w/s | 每秒写 IOPS | - |
| (4) | rkB/s | 每秒读 KB | 吞吐 |
| (5) | wkB/s | 每秒写 KB | 吞吐 |
| (6) | rrqm/s | 合并的读请求数 | 越多越好(说明顺序读 OK) |
| (7) | wrqm/s | 合并的写请求数 | 同上 |
| (8) | r_await | 读平均延迟(ms) | > 10ms 慢 |
| (9) | w_await | 写平均延迟 | 同上 |
| (10) | aqu-sz | 平均队列深度 | > 1 表示排队 |
| (11) | %util | 设备繁忙占比 | 持续 > 80% = 瓶颈(HDD/SATA SSD)/ NVMe 不准 |
注:老版 iostat 列名略不同(
avgqu-sz/await/r_await等),意思类似。
2. 重点字段深入
%util —— 不能简单解读
%util 含义:N 秒内设备至少有一个 I/O 在进行的时间占比
| 盘类型 | %util = 100% 意味着 |
|---|---|
| HDD | 真的瓶颈、等队列 |
| SATA SSD | 接近瓶颈 |
| NVMe SSD | 不一定瓶颈——NVMe 有多队列、可并发处理 |
NVMe 看 await + aqu-sz 更准。100% %util + 0.5ms await + 0.2 aqu-sz = 完全没瓶颈、只是一直有 I/O。
await —— 真实延迟
r_await / w_await = 平均每个 I/O 完成时间(从入队到完成)
= 等队列时间 + 设备处理时间
业务影响最大的就是 await。指标参考:
| 盘类型 | 期望 await |
|---|---|
| 高端 NVMe | < 0.5 ms |
| 普通 NVMe | < 2 ms |
| SATA SSD | < 5 ms |
| 7200 转 HDD | 10-20 ms |
| 慢 / 报警 | > 20 ms |
数据库 fsync 慢 → 看 w_await。
aqu-sz —— 队列深度
平均队列深度 = ∫(每时刻队列长度) / 时间
- < 1:没排队、I/O 来一个处理一个
- = 1:有时排队
1:经常排队、I/O 比设备处理快
8:严重排队
应用 fsync 同步写场景 aqu-sz 通常很小;数据库 / 异步写场景可能大。
3. 几种常见模式
%iowait 35.0
Device r/s w/s r_await w_await aqu-sz %util
nvme0n1 500 1000 15.0 25.0 10.0 98.0
读 / 写延迟都高、队列深 → 磁盘瓶颈。
修法:
- 加 IOPS 配置(云盘升级)
- 用更快的盘(NVMe 替代 SATA)
- 应用层批量写 / 异步 / 加 cache
[14:30:00] %util 5
[14:30:10] %util 90 ← 突发
[14:30:20] %util 5
短时突发不要紧。持续看一段时间:
iostat -xz 1 60 # 跑 60 秒看趋势
Device r_await w_await aqu-sz %util
nvme0n1 0.3 0.5 0.2 100.0
%util 100% 但 await 0.3ms / aqu-sz 0.2 = 不是瓶颈,只是一直有 I/O。NVMe 多队列特性。
Device r/s w/s rkB/s wkB/s
sda 5000 8000 20000 40000
↑^^^^ ↑^^^^
平均每 IO 只 4-5 KB
平均 IO 4-5 KB → 大量小文件 / 数据库小事务。
如果 await 高 → 看是 IOPS 极限到了。
Device r/s w/s rkB/s wkB/s rareq-sz wareq-sz
sda 50 100 50000 200000 1000 2000
^^^^^^^^^^^^^^^^^
平均每 IO 1MB / 2MB
低 IOPS + 高吞吐 + 大 IO 块 = 大文件顺序操作(视频 / 备份)。
吞吐到盘的极限(SATA ~500MB/s、NVMe 多 GB/s)就是瓶颈。
4. 常用参数变体
iostat # 简单概览
iostat -x 1 # 详细 + 持续 1s
iostat -x 1 5 # 详细 + 1s 间隔、跑 5 次
iostat -xz 1 # + 跳过 0 设备
iostat -xm 1 # MB 单位(不是 KB)
iostat -xh 1 # human readable
iostat -xz -p sda 1 # 只看 sda(含分区)
iostat -d -x 1 # 只看 disk(不显示 CPU)
iostat -c -x 1 # 只看 CPU
iostat -y 1 1 # 跳过开机来的累计快照、只看实时
-y 跳过开机汇总(脚本必加)
$ iostat -x 1 5
Linux ... (m4) 2026-05-27 _x86_64_ (4 CPU)
# 第 1 行:开机以来的累计 ← 通常没意义
Device r/s w/s ... %util
nvme0n1 100 200 ... 50.0
# 后面才是 1s 间隔的实时
...
-y 跳过第一段、直接给"现在":
iostat -xz -y 1 1 # 一次性、不要累计、只看 1 秒采样
写监控脚本必加 -y。
5. 实战场景
场景 1:判断节点是不是磁盘瓶颈
$ ssh m4 'top'
%Cpu(s): 5.0 us, 2.0 sy, ..., 30.0 wa
^^^^
wait 高!
$ ssh m4 'iostat -xz 1 5'
Device r/s w/s r_await w_await aqu-sz %util
nvme0n1 500 1000 15.0 25.0 10.0 98.0
^^^^^^ ^^^^^^^^^^^^^^^^
延迟高 + 队列深 = 真磁盘瓶颈
→ 升级盘 / 换 SSD / 加节点分流。
场景 2:找哪个 LV / PV 慢
$ iostat -xz -p sda 1 # 看 sda + 它所有分区
Device r/s w/s r_await w_await %util
sda 500 1000 10 20 80
sda1 5 10 1 2 1
sda2 495 990 10 20 80 ← sda2 慢
如果用 LVM:
$ iostat -xz -p dm-0 1 # device mapper 设备
$ iostat -xz | grep -E "data--vg"
场景 3:测试新盘性能
# 准备
mkfs.ext4 /dev/nvme1n1
mount /dev/nvme1n1 /mnt/test
# 跑测试
fio --name=test --rw=randwrite --bs=4k --size=10G --runtime=60 \
--filename=/mnt/test/file --ioengine=libaio --direct=1 --iodepth=32
# 同时看 iostat
iostat -xz -p nvme1n1 1
监控随机写 4K IOPS(数据库典型 workload)。
场景 4:监控 K8s pod 的 I/O
# Pod 里跑 dd / fio
$ kubectl exec my-pod -- dd if=/dev/zero of=/data/test bs=1M count=1000 &
# 节点上看
$ ssh m4 'iostat -xz 1'
看具体哪个底层盘对应这个 PV → 性能怎么样。
场景 5:长跑监控写日志
# 每秒一次、写 csv 文件
iostat -xz -t 1 86400 > /var/log/iostat.log &
# 后台跑 24h、分析趋势
或者用 sar(同 sysstat 包):
sar -d 60 1440 > daily.log # 每分钟、跑 24h
更适合长期监控。
6. 反面教材
反面 1:只看 %util 不看 await
%util 100 ← 看到 100% 就慌
await 0.5
NVMe / 现代 SSD 经常 100% util 但延迟极低、不是瓶颈。看 await 才是真理。
反面 2:用 iostat 第 1 段做分析
$ iostat -xz
# 第 1 段是开机以来累计 → 对当前没参考价值
加 -y 跳累计、加 1 5 这种采样间隔。
反面 3:iostat 看不到云盘
云上某些虚拟化(特别 Xen / AWS classic)的盘设备命名特殊。
$ iostat -xz
# 看不到云盘?
$ lsblk
# xvda(不是 sda)
$ iostat -xz -p xvda 1
或者直接看完整设备:
$ iostat -xz -p ALL
反面 5:用 iostat 不加 root
非 root 一般也能跑 iostat(只读 /proc)但少看到一些字段。生产排错用 sudo。
7. 相关 / 互补命令
| 工具 | 看什么 |
|---|---|
| iostat | 节点级 disk + CPU 综合 |
| iotop | 哪个进程在 I/O |
| vmstat | 内存 + swap + 进程 + I/O 综合 |
| mpstat | 多 CPU 详细 |
| sar | 历史采样、长跑监控 |
| fio | 性能基准测试 |
| biotop (bcc) | eBPF 实时 |
| pidstat -d | 进程级 I/O 统计 |
dstat | iostat + vmstat 合一、彩色友好 |
dstat —— 更友好的 iostat
apt install -y dstat
dstat -cdng # CPU + 磁盘 + 网络 + 内存
dstat -d --top-io # 看哪些进程 I/O 大
dstat 单工具看全部指标、对人友好。但生产监控还是用 iostat + 监控系统(Prometheus node-exporter)。
Prometheus node-exporter 等价 metric
# 写 IOPS
rate(node_disk_writes_completed_total[1m])
# 读 IOPS
rate(node_disk_reads_completed_total[1m])
# 写延迟(等价 w_await)
rate(node_disk_write_time_seconds_total[1m]) / rate(node_disk_writes_completed_total[1m])
# %util
rate(node_disk_io_time_seconds_total[1m])
详见 prometheus.md。