﻿# iostat —— 磁盘 IO 与 CPU 概览（定位 iowait 瓶颈）

## 这个工具是做什么的

`sysstat` 套件成员。当 `top`/`vmstat` 显示 `wa`(iowait) 高、`b` 队列大时，用 `iostat` 确认**是哪块盘、多忙、延迟多高、是随机小 IO 还是顺序大 IO**。它到设备级，落到进程还需 `iotop`/`pidstat -d`。

## 可以回答什么问题

| 问题 | 怎么用 |
|------|--------|
| 是哪块磁盘在忙？ | `iostat -x 1` 按设备看 `%util` 和 `await` |
| 磁盘 IO 延迟高不高？ | `r_await`/`w_await` 列（单位 ms） |
| 是随机小 IO 还是顺序大 IO？ | `rareq-sz`/`wareq-sz`：几 KB = 随机，几百 KB = 顺序 |
| IOPS 多少？吞吐量多少？ | `r/s`/`w/s` = IOPS，`rkB/s`/`wkB/s` = 吞吐 |
| SSD/NVMe 真的到瓶颈了吗？ | 别看 `%util`，看 `await` 和 `aqu-sz`（`%util` 在多队列盘上会失真） |

## 数据来源

- **来源文件**：每个块设备的读写次数、扇区数、IO 耗时、队列时间取自 `/proc/diskstats`（等价 `/sys/block/*/stat`）；顶部 CPU 行取自 `/proc/stat`。
- **采集方式**：按间隔读两次这些累计计数，**做差**算出 IOPS（`r/s`/`w/s`）、吞吐（`kB/s`）、延迟（`await`）、`%util` 等。
- **由此决定的特性**：数据到**设备级**为止，看不到"哪个进程在读写"——要落到进程得配 `iotop` 或 `pidstat -d`；且 `%util` 在能并行处理请求的 SSD/NVMe 上会失真（见正文的坑）。

```bash
yum install sysstat / apt install sysstat
```

## 一、用法

```bash
iostat                   # 一次性：CPU 汇总 + 各设备开机以来平均
iostat 1                 # 每 1 秒刷新（CPU 行 + 设备行）
iostat -x 1              # 扩展模式（最常用，含 %util、await 等关键列）
iostat -xd 1             # -d 只看磁盘，不显示 CPU 行
iostat -xm 1             # -m 单位用 MB/s（默认 KB/s 或块）
iostat -x 1 sda nvme0n1  # 只看指定设备
iostat -xh 1             # -h 人类可读、每设备纵向排列（新版，宽表看不过来时好用）
iostat -xp 1             # -p 展开到分区级（sda1、sda2...）
```

> 第一行是开机以来平均，看第二行起的实时值。

## 二、`-x` 扩展模式字段全解

```bash
Device  r/s   w/s   rkB/s   wkB/s  rrqm/s wrqm/s r_await w_await aqu-sz rareq-sz wareq-sz  %util
sda    12.0 340.0   192.0 43520.0    0.0   15.0    0.30    8.50   2.90    16.0    128.0   96.20
```

| 字段 | 含义 | 判读 |
|------|------|------|
| `r/s` `w/s` | 每秒完成的读/写请求数（**IOPS**）| |
| `rkB/s` `wkB/s` | 每秒读/写 KB（**吞吐**）| |
| `rrqm/s` `wrqm/s` | 每秒被内核合并的读/写请求数 | 合并多 = 有相邻请求被攒着一起下发（顺序 IO 特征）|
| `r_await` `w_await` | 读/写平均延迟（**ms**，含排队+服务时间）| **最关键**。机械盘正常个位数~十几 ms，SSD 应 <1ms；偏高 = 盘慢或在排队 |
| `aqu-sz` | 平均队列深度（旧版 `avgqu-sz`）| >1 且持续 = 请求在排队等设备 |
| `rareq-sz` `wareq-sz` | 平均每次请求大小 KB | **小（几 KB）= 随机小 IO**，效率低；大（几百 KB）= 顺序大 IO |
| `%util` | 设备繁忙时间占比 | 见下方坑 |

## 三、判断口诀

| 现象 | 结论 |
|------|------|
| `%util` 接近 100% + `await` 高 | 磁盘打满，是瓶颈 |
| `await` 高但 `%util` 不高 | 单次请求太大、或后端存储（网络盘/RAID）慢 |
| `r/s`/`w/s` 很高但 `rareq-sz` 很小 | **大量随机小 IO** → 合并写、加缓冲、换 SSD |
| 只有 `kB/s` 高、`await` 正常 | 顺序大 IO，通常健康（如备份、大文件拷贝）|
| `w_await` 远大于 `r_await` | 写瓶颈（如频繁 fsync、日志刷盘）|

## 四、`%util` 的重要陷阱

`%util` = 设备至少有一个请求在处理的时间占比。

- **机械盘（单队列）**：`%util` 接近 100% 基本等于打满，参考意义大。
- **SSD/NVMe（多队列、可并行）**：能同时处理几十上百个请求，`%util` 到 100% 也**不代表**真的满了——它只表示"一直有活干"，不代表并行度用尽。判断 NVMe 是否到瓶颈要看 `await` 是否随负载明显上升、`aqu-sz` 是否堆积，而非只看 `%util`。

## 五、结合本仓库与定位到进程

```bash
./cpu_demo &                # 选场景 2（狂写 /tmp 文件）
iostat -x 1                 # 观察对应盘的 w/s、wkB/s、w_await 上升
# 确认哪块盘忙后，落到进程：
pidstat -d 1                # 看 kB_wr/s 最高的进程
sudo iotop -o               # 或交互式直接看
```

**标准排查链**：`top`/`vmstat` 见 `wa` 高 → `iostat -x 1` 定位哪块盘、是随机还是顺序、延迟多少 → `iotop`/`pidstat -d` 找到罪魁进程 → `strace -e trace=read,write,fsync -p <PID>` 看它在读写什么、多频繁。

## 六、关键指标速查

| 指标 | 缩写/英文 | 参考值（按设备类型） | 异常信号 |
|------|----------|---------------------|---------|
| 读/写 IOPS | `r/s` `w/s` / Read/Write IOPS | HDD: 100-200, SATA SSD: 50K-100K, NVMe: 500K-1M | 接近/超过设备规格上限 |
| 读/写吞吐 | `rkB/s` `wkB/s` / Throughput | HDD: 150-250 MB/s, SATA SSD: 500-550 MB/s, NVMe: 3000-7000 MB/s | 接近设备带宽上限 |
| 平均延迟 | `await` / Avg Wait Time | HDD: 5-20ms, SATA SSD: 0.05-0.5ms, NVMe: 0.01-0.1ms, Optane: <0.01ms | 持续高于参考值 → 盘慢或排队 |
| 读延迟 | `r_await` / Read Latency | 同上 | 远高于写 → 读密集型瓶颈 |
| 写延迟 | `w_await` / Write Latency | 同上 | 远高于读 → 写拥塞/频繁 fsync |
| 平均队列深度 | `aqu-sz` / Avg Queue Size | HDD: <2, SSD: 可 >4（多队列盘正常） | HDD > 2 且持续 → 堆积；NVMe > 32 且 await 不升 → 盘有余力 |
| 设备占用率 | `%util` / Device Utilization | — | 机械盘近 100% → 打满；SSD/NVMe 不可信（看 await+aqu-sz） |
| 平均请求大小 | `rareq-sz` `wareq-sz` / Avg Req Size | 4K-64K（随机小 IO），128K-1M（顺序大 IO） | 几 KB → 随机小 IO，效率低；几百 KB → 顺序大 IO，健康 |
| 合并请求数 | `rrqm/s` `wrqm/s` / Merge Rate | 有合并=正常 | 合并不多 → 应用在发大量零散 IO |
| CPU iowait | `%iowait` | < 5% | > 20% → IO 是瓶颈（但 SSD/NVMe 上 iowait 容易虚高，配合 await 判断） |

> **IOPS/吞吐/延迟速记**：HDD → ~200 IOPS / ~200 MB/s / ~10ms · SATA SSD → ~100K IOPS / ~500 MB/s / ~0.1ms · NVMe Gen4 → ~1M IOPS / ~6GB/s / ~0.02ms。跨三个数量级，`iostat -x 1` 的 `r/s`、`rkB/s`、`await` 对号入座。

## 七、常见排查方法与分析

### 7.1 await 高 → 确认是盘慢还是排队

```bash
iostat -x 1 → await 持续高
  → 同时看 aqu-sz:
    → aqu-sz > 2 → IO 请求在排队（盘处理不过来）
    → aqu-sz < 1 但 await 高 → 单次请求太大/后端存储慢
  → 看 r_await 和 w_await 分拆 → 读瓶颈还是写瓶颈
```

### 7.2 随机小 IO vs 顺序大 IO

```bash
iostat -x 1 → rareq-sz / wareq-sz
  → 几 KB 且 r/s 很高 → 随机小 IO（效率低）
    → 合并写、加缓冲、换 SSD
  → 几百 KB 且 await 正常 → 顺序大 IO（通常健康）
```

### 7.3 SSD/NVMe 瓶颈判断（不看 %util）

```bash
iostat -xdm 1 /dev/nvme0n1 → 关注 await 和 aqu-sz
  → %util 可能一直接近 100%（SSD/NVMe 多队列，此指标失真）
  → 真正瓶颈看：
    → await 是否随负载增加而明显上升
    → aqu-sz 是否持续堆积
    → r/s + w/s 是否接近盘规格上限
```

### 7.4 写拥塞定位

```bash
iostat -x 1 → w_await >> r_await
  → iotop -o → 找 DISK WRITE 最高的进程
    → strace -e trace=write,fsync -p <PID> → 是否频繁 fsync
      → 频繁 fsync → 考虑异步写入或批量提交
```

## 八、交叉引用

- **IO 瓶颈入口**：[top](/tools/cpu/top.md) `wa` 列 → [vmstat](/tools/cpu/vmstat.md) `b` 列
- **进程级 IO**：[iotop](/tools/disk/iotop.md)（哪个进程在读写）→ [pidstat](/tools/cpu/pidstat.md) `-d`（无 root 替代）
- **系统调用追踪**：[strace](/tools/code/strace.md)（看进程在做什么文件操作）
- **数据源**：[procfs](/tools/proc/procfs.md) §三（/proc/diskstats 是 iostat 的数据来源）
- **IO 调度器调优**：[kernel-tuning](/tools/proc/kernel-tuning.md) §二（/sys/block/.../queue/scheduler）

## 九、CPU 行

`iostat` 顶部还有一行 CPU：`%user %nice %system %iowait %steal %idle`，含义同 `top`。其中 `%iowait` 是判断"CPU 是不是在干等 IO"的入口指标。

