Linux 服务器磁盘 IO 性能排查指南
磁盘 IO 瓶颈是服务器性能问题中最隐蔽、也最容易被误判的一类。 很多人看到 load 高、响应慢,第一反应是 CPU 或内存,但实际上 70%+ 的“服务器变慢”最终都能追溯到磁盘 IO 等待(尤其是随机读写场景)。
以下是目前最系统、最高效的排查路径,按快速判断 → 定量分析 → 定位进程 → 根因分类 → 优化闭环的顺序组织。
第一步:30 秒快速判断是否有 IO 瓶颈
| 顺序 | 命令 | 核心观察指标(异常阈值) | 如果异常,指向 |
|---|---|---|---|
| 1 | iostat -x 1 5 或 iostat -xmdz 1 5 | %util > 80–90%(单个盘),await > 10–20 ms,svctm 高 | 很可能有 IO 瓶颈 |
| 2 | top / htop | wa(iowait)> 15–30% 持续 | 进程在等磁盘 |
| 3 | vmstat 1 5 | wa > 20%,b(阻塞进程)较多,bi/bo 非零且较大 | IO 等待队列积压 |
| 4 | uptime | load 高,但 CPU us+sy 不高,wa 高 | 典型“假高负载,真 IO 瓶颈” |
一句话判断标准(最重要):
- %util 接近 100% + await > 10–20ms → 磁盘真的饱和了
- wa/iowait 高 + %util 不高 → 可能是少量非常慢的 IO 请求拖死整个系统(常见于机械盘或有坏块的 SSD)
- %util 低 + await 极高 → 单次 IO 延迟极高(网络存储、NFS、坏道、raid 降级)
第二步:区分是哪种 IO 模式导致的瓶颈
用以下命令组合判断 IO 模式:
| IO 模式 | 典型特征(iostat -x) | 常见业务场景 | 关键指标对比 |
|---|---|---|---|
| 随机读 | r/s 高,%util 高,await 中等~高,rMB/s 不高 | 数据库(MySQL/PostgreSQL 索引扫描) | r/s >> w/s,await 10–50ms |
| 随机写 | w/s 高,%util 高,await 较高,wMB/s 不高 | 日志写入、Redis AOF、数据库 binlog、WAL | w/s 高,await > 20–100ms |
| 顺序读 | rMB/s 很高,%util 中等,await 很低 | 大文件拷贝、备份、视频流读取 | rMB/s 接近磁盘理论值,await < 5ms |
| 顺序写 | wMB/s 高,%util 中等~高,await 低~中等 | 大文件写入、Hadoop 数据导入 | wMB/s 高,await < 10ms |
| 混合负载 | r/s 和 w/s 都高,%util 高,await 中~高 | 高并发 OLTP 数据库、日志 + 索引同时写 | r/s ≈ w/s,await 15–60ms |
快速口诀:
- r/s 很高 + await 高 → 随机读瓶颈(最常见数据库场景)
- w/s 高 + await 极高 → 随机写瓶颈(日志、binlog、WAL)
- %util 高但吞吐(rMB/s + wMB/s)低 → 随机 IO 主导
- %util 不高但 await 极高 → 单次 IO 极慢(网络存储、坏盘)
第三步:定位是哪个进程/服务在制造 IO
| 工具 | 命令示例 | 优点 / 使用场景 | 输出重点 |
|---|---|---|---|
| iotop(首选) | sudo iotop -o -P(只显示有 IO 的) | 实时、直观,像 top 一样看 IO | DISK READ / DISK WRITE 列 Top 进程 |
| pidstat | pidstat -d 1 5 | sort -k 4 -nr | 可脚本化、历史统计、精确到线程 | kB_rd/s、kB_wr/s 最高的进程/线程 |
| blktrace + blkparse | blktrace -d /dev/nvme0n1 -a issue | 极致精确、能看到每个 IO 的详细信息 | 需要后处理,适合深度分析 |
| bpftrace | 一行脚本追踪特定进程或设备 IO | 零开销、内核级、可定制 | 延迟分布、热点文件、进程 IO 量 |
| lsof + grep | lsof /dev/nvme0n1 或 `lsof | grep deleted` | 找被删除但还在写的文件(最常见日志文件) |
推荐组合:
- 先 iotop -o 看实时谁在写/读最多
- 再 pidstat -d 1 10 | sort -k 4 -nr | head -15 确认 10 秒内累计量
- 如果看到大量 deleted 文件 → lsof | grep deleted 找元凶
第四步:根因分类与针对性优化
| 根因分类 | 典型表现(iostat + 进程) | 常见业务/场景 | 优化优先级 & 方案(从简单到复杂) |
|---|---|---|---|
| 日志狂写 | w/s 高,%util 高,大量写小块 | nginx access/error、应用 debug 日志 | 1. 降日志级别 2. logrotate + size 限制 3. 异步日志 4. 日志 → tmpfs 或单独盘 |
| 数据库慢查询/索引缺失 | 随机读 r/s 高,await 20–100ms | MySQL/PostgreSQL 未命中索引、全表扫描 | explain + 加索引、调 innodb_io_capacity、加 buffer pool |
| binlog / WAL / AOF 同步写 | 随机写 w/s 高,await 极高 | MySQL sync_binlog=1、Redis appendfsync always | 调 sync_binlog=0 或 1000、appendfsync everysec、开启 write cache |
| 大量小文件元数据操作 | r/s 高但 rMB/s 低,dentry/inode slab 膨胀 | 高并发上传小文件、git 仓库、日志切割碎片 | 调 vm.vfs_cache_pressure、用 xfs/ext4 大块、减少小文件数 |
| 被删文件仍在写(deleted) | iostat 写很高,但 du 看不到占用 | 程序打开日志文件后被 logrotate 删掉 | 重启对应进程,或 kill -USR1 让服务重新打开日志文件 |
| 网络存储/NFS/EBS 延迟 | await 极高(50–500ms),%util 不一定高 | 云盘、NFS、ceph、EBS gp2/gp3 超预算 | 换 io2/io2 Block Express、加大 IOPS、就近部署、加本地缓存 |
| 磁盘本身老化/坏块 | await 极高、偶发 i/o error 日志 | 机械盘老化、SSD 写放大、坏块 | smartctl 检查健康、坏块重映射、更换磁盘 |
第五步:验证 & 长期监控建议
验证效果(优化后必须看):
- iostat -x 1 5 的 %util 和 await 是否显著下降
- vmstat 的 wa 是否降低
- 业务延迟 / QPS 是否恢复
长期监控指标(推荐加到 Prometheus / Grafana):
- node_disk_io_time_seconds_total
- node_disk_io_time_weighted_seconds_total
- node_disk_reads_completed_total & writes
- await / svctm / %util per disk
- 告警:单个盘 %util > 85% 持续 5min 或 await > 20ms 持续 3min
一句话总结排查口诀:
iostat -x 看 %util + await → iotop/pidstat 找进程 → 区分读/写/随机/顺序 → 看日志/数据库/网络存储/小文件元数据 → 优化写策略/加索引/换盘/分盘
这是目前生产环境中最常使用的磁盘 IO 排查路径,能覆盖 90%+ 的线上 IO 瓶颈场景。