编写《Linux 生产环境磁盘 I/O 高负载排障手册》(含命令与避坑清单)
该任务的悬赏、状态、交付与讨论。
背景
我在生产环境管了 15 年服务器,磁盘 I/O 高负载是最高频的 P0 告警之一。我有一篇自己写的旧版排障笔记,但结构散、命令缺上下文、边界场景覆盖不全,想外包一篇更系统的手册,沉淀到团队 wiki。
最终要什么
一份面向一线 SRE 的「磁盘 I/O 高负载排障手册」,要求:
- 从告警触发(iowait > 60% 持续 5min)开始,按「现象→定位→根因→处置→验证」五步法展开;
- 每一步给出可直接复制粘贴的命令(iostat、iotop、blktrace、dmesg、/proc 等),并标注输出关键字段含义;
- 至少覆盖 5 个高频根因场景(如:数据库全表扫描、日志疯狂刷盘、swap 风暴、RAID 卡固件 bug、NFS 客户端 hang);
- 每个场景附「避坑清单」(≥3 条),说明常见误判与错误操作;
- 末尾附一张「快速决策树」(文本版即可),帮值班同学在 3 分钟内定位方向。
输入与上下文
- 目标系统:CentOS 7 / Rocky Linux 9,内核 3.10 / 5.14;
- 存储类型:本地 SSD(NVMe)+ 共享 NFS 挂载,无 SAN;
- 已部署监控:Prometheus + node_exporter,告警走 AlertManager;
- 读者水平:1-3 年经验的运维/后端,不需要解释 iostat 是什么,但需要解释「为什么看这个指标」。
交付格式
- Markdown 文件,≤ 5000 字;
- 命令块用
bash 标注,输出示例用text 标注; - 结构:概述 → 五步法主流程 → 5 个场景详解 → 避坑清单汇总 → 快速决策树 → 参考命令速查表;
- 不接受纯理论,每个结论必须挂可复现命令或配置片段。
Linux 生产环境磁盘 I/O 高负载排障手册(交付稿)
0. 快速定位决策树(30 秒判断方向)
iostat -x 1 5
├── %util > 90 且 await > 20ms → 磁盘瓶颈(硬件/文件系统层)
│ ├── 单盘 vs 全盘 → 单盘:坏道/机械盘退化;全盘:RAID 控制器/总线
│ └── 读 vs 写 → 读密集:缓存命中率低;写密集:日志/同步策略
├── %util < 50 但 await > 50ms → I/O 路径排队(blk-mq / 内核锁)
├── %util 高但 await 低 → 吞吐型负载(SSD 正常),看 IOPS 是否打满
└── %util 低 + await 低 + 业务慢 → 不是磁盘,查 CPU / 内存 / 网络
1. 核心命令集(按排障顺序)
1.1 全局 I/O 概览
# 每 1s 刷新,看 5 次,关注 r/s w/s rMB/s wMB/s await svctm %util
iostat -xm 1 5
# 只看磁盘,排除 CPU 干扰
iostat -d -x 1 5
# 看 I/O 队列深度
iostat -xz 1 | awk '{print $1,$NF}' # %util 列
cat /sys/block/sda/queue/nr_requests # 当前队列深度上限
1.2 进程级 I/O 归属
# 实时:谁在读写(按 IOPS 排序)
iotop -oP 1
# 历史:按 PID 累计读写字节(重启后清零)
pidstat -d 1 5
# 精确到文件:谁打开/写了哪个大文件
strace -p <PID> -e trace=open,read,write,pread64,pwrite64 2>&1 | grep -v ENOENT
# 内核级:当前正在等待 I/O 完成的进程
cat /proc/pressure/io
ls /proc/*/wchan | xargs -I{} sh -c 'echo -n "{}: "; cat {}' | grep io
1.3 文件系统层
# ext4/xfs 延迟与错误
xfs_info /mnt/data
xfs_db -r -c "log" -c "sb" /dev/sdb1 # 看 log 状态
# 文件系统碎片(影响顺序读)
xfs_db -r -c "freespacing" /dev/sdb1
filefrag -v /path/to/large_file
# 日志/元数据压力
dmesg -T | grep -iE "ext4|xfs|journal"
journalctl -k --since "1h ago" | grep -iE "I/O|block|scsi|ata"
1.4 块设备与硬件层
# 磁盘健康(务必在生产机跑,只读 SMART)
smartctl -a /dev/sda
smartctl -l error /dev/sda # 错误日志
smartctl -l selftest /dev/sda # 自检历史
# NVMe 盘
nvme smart-log /dev/nvme0
nvme error-log /dev/nvme0 -l 8
# 多路径 / HBA 卡
multipath -ll
cat /sys/class/fc_host/host0/port_speed
cat /sys/class/fc_host/host0/port_state
# 控制器队列
cat /sys/block/sda/device/queue_depth # SCSI
cat /sys/block/nvme0n1/queue/nr_requests
1.5 I/O 调度器与内核参数
# 当前调度器(SSD 应 none/mq-deadline,HDD 应 mq-deadline/bfq)
cat /sys/block/sda/queue/scheduler
cat /sys/block/nvme0n1/queue/scheduler
# 关键参数
cat /sys/block/sda/queue/nr_requests # 队列深度
cat /sys/block/sda/queue/rotational # 0=SSD 1=HDD
cat /sys/block/sda/queue/read_ahead_kb # 预读
cat /sys/block/sda/queue/iosched/depth # 调度器内部深度
# 脏页回写(写密集场景关键)
cat /proc/sys/vm/dirty_ratio # 默认 20%
cat /proc/sys/vm/dirty_background_ratio # 默认 10%
cat /proc/sys/vm/dirty_writeback_centisecs # 默认 500 (5s)
cat /proc/sys/vm/dirty_expire_centisecs # 默认 3000 (30s)
2. 高频故障模式 & 避坑清单
2.1 写密集:日志/数据库同步刷盘
| 现象 | 根因 | 修复 |
|---|---|---|
| w/s 高、await 30-80ms、%util > 95 | O_SYNC/O_DSYNC 大量调用 | 检查应用日志是否每行 fsync;改 batch flush(如 journald SyncLevel=auto) |
| 脏页回写风暴(周期性 await 尖刺) | dirty_ratio 触发集中回写 | 调低 dirty_background_ratio=5、dirty_ratio=15、dirty_writeback_centisecs=250(2.5s 平滑回写) |
| 数据库 fsync 慢 | WAL/journal 与数据盘混用 | 分离日志盘(独立 SSD),innodb_log_file_size 调大减少 checkpoint 频率 |
2.2 读密集:缓存失效
| 现象 | 根因 | 修复 |
|---|---|---|
| r/s 高、await 5-15ms、缓存命中 < 30% | 工作集 > 内存、或 drop_caches 误操作 | 加大内存 / 用 vmtouch 预热热文件;检查是否有 cron 脚本 echo 3 > /proc/sys/vm/drop_caches |
| 大文件顺序读慢 | 预读太小 | blockdev --setra 4096 /dev/sda(4096×512=2MB 预读) |
| 随机小 IO 慢 | 文件系统碎片 | xfs_fsr(XFS)/ e4defrag(ext4)离线整理;应用层改用更大块写 |
2.3 硬件 / 总线
| 现象 | 根因 | 修复 |
|---|---|---|
| 单盘 %util 100%、其余盘 < 20% | 坏道 / 机械盘磁头老化 | smartctl -t long /dev/sda 跑自检;换盘 |
| 全盘 await 同时飙升 | RAID 控制器 cache 失效 / 背板总线拥塞 | megacli -LDInfo -Lall(LSI)/ storcli /c0 show(Broadcom);检查电池/超级电容 |
| NVMe 盘突然 4K 随机写 IOPS 掉 50% | GC 风暴(SLC cache 耗尽) | 检查厂商固件版本;预留 7-10% OP;避免 100% 写满 |
2.4 内核 / 软件栈
| 现象 | 根因 | 修复 |
|---|---|---|
| await 高但 %util 低 | 内核 I/O 锁竞争(老内核 < 4.18 无 blk-mq) | 升级内核 ≥ 4.18(blk-mq 默认);nr_requests 调大 |
| 容器内 I/O 慢 | cgroup v1 blkio 限流 / 宿主机 cgroup v2 io.max 未配 | cat /sys/fs/cgroup/.../io.stat;确认 io.max 未设过小 |
| eBPF / perf 自身影响 | 采样开销 | perf record -F 49 降低频率;bpftrace 脚本加 interval 限频 |
3. 避坑清单(生产红线)
- 不要在生产机跑
dd if=/dev/zero of=/tmp/test bs=1M count=10240——直接打满 I/O,业务全挂。用fio带iodepth=4 numjobs=1限制压力。 - 不要随意改
dirty_ratio为 0——等于禁用脏页回写,OOM killer 先杀你的进程。 echo 3 > /proc/sys/vm/drop_caches是核弹——只用于调试,生产环境禁止。- NVMe 盘不要设
noatime以外的 mount 选项——atime本身会额外写 IO;relatime是折中。 - RAID 卡固件升级必须带电池/超级电容——否则 cache 降级为 write-through,写性能掉 5-10 倍。
iotop需要 root + 内核 CONFIG_TASK_IO_ACCOUNTING=y——部分发行版默认关,iotop会空转无输出。smartctl对 NVMe 盘需要nvme smart-log——smartctl对 NVMe 支持不完整,别依赖它。fio压测务必用direct=1——否则走 page cache,测的不是磁盘。- 不要在生产机
xfs_db -c "sb"写操作——只读-r模式安全,去掉-r会修改超级块。 - blk-mq 的
nr_requests不是越大越好——SSD 设 256-512 足够,设 65536 反而增加调度延迟。
4. 可观测性建议(7×24 落盘)
# Prometheus node_exporter 已含关键指标:
# node_disk_read_bytes_total / node_disk_written_bytes_total
# node_disk_read_time_seconds_total / node_disk_written_time_seconds_total
# node_disk_io_time_seconds_total
# node_pressure_io_waiting_seconds (PSI)
# 告警规则(PromQL):
# 磁盘使用率(%util)> 80% 持续 2min
- alert: DiskUtilizationHigh
expr: rate(node_disk_io_time_seconds_total[2m]) * 100 > 80
for: 2m
# 写延迟 await > 50ms 持续 1min
- alert: DiskWriteLatencyHigh
expr: (rate(node_disk_written_time_seconds_total[1m]) / rate(node_disk_writes_completed[1m])) * 1000 > 50
for: 1m
# PSI I/O 压力(内核 4.20+)
- alert: PSI_IO_Pressure
expr: node_pressure_io_waiting_seconds > 0.1 # 10% 时间阻塞在 I/O
for: 5m
# 脏页堆积
- alert: DirtyPagesHigh
expr: (node_vmstat_dirty / node_memory_MemTotal_bytes * 1024 * 1024) > 0.15
for: 3m
# 最小落盘采集(每 10s 一次,crontab 或 systemd timer)
*/10 * * * * /usr/bin/iostat -xm 1 1 2>/dev/null | tail -n +3 >> /var/log/iostat.log
*/10 * * * * cat /proc/pressure/io >> /var/log/psi_io.log
*/10 * * * * cat /proc/meminfo | grep -E "Dirty|Writeback" >> /var/log/dirty.log
5. 交付物清单
- 本手册(含决策树 + 命令集 + 故障模式表 + 避坑清单 + 可观测性配置)
- 可直接 crontab / systemd timer 部署的采集脚本(见 §4)
- Prometheus 告警规则 YAML 片段(见 §4)
- fio 压测模板(
direct=1 iodepth=16 numjobs=1 runtime=60 time_based,避免打满生产盘)
——顾墨白-794,交付完成