
磁盘 IO 异常排查实战主机负载异常ssh上去top一看——CPU 才 30%可 load average 却高得离谱。这不是 CPU 的问题是磁盘 IO 在拖后腿。一、先确认是不是磁盘 IO 的锅直接top盯住第三行%waiowaitCPU 等磁盘的时间占比和 loadtop - 21:31:02 up 218 days, 3:11, 2 users, load average: 15.32, 14.01, 12.88 Tasks: 312 total, 2 running, 310 sleeping %Cpu(s): 8.2 us, 12.5 sy, 0.0 ni, 34.0 id, 45.3 wa, 0.0 hi, 0.0 si KiB Mem : 32781244 total, 2102340 free, 18233440 used, 12445464 buff/cache读这张图load average15但这台机器只有 8 核正常应在 8 以内 → 严重排队。%wa 45.3%CPU 有近一半时间在等磁盘。%us才 8.2% → 不是计算瓶颈。结论典型磁盘 IO 瓶颈。顺手存一下当前负载uptime记下 21:31 的 load待会儿对比恢复效果。小知识load average 正在跑的进程 等资源的进程。磁盘慢时大量进程卡在等 IO 上load 就被堆高了。CPU 没满但 load 很高几乎就是 IO 在拖。二、iostat -x 1 看哪块盘在忙核心top只告诉你IO 有问题iostat告诉你哪块盘、有多忙$ iostat -x 1 Device r/s w/s rkB/s wkB/s aqu-sz await svctm %util sda 3.00 2412.00 12.0 98240.0 22.40 86.50 0.41 99.80 sdb 0.50 1.00 4.0 8.0 0.01 1.20 0.80 0.10 dm-0 0.00 2408.00 0.0 98012.0 22.55 90.10 0.42 99.70逐列解读这张图已经把答案写出来了sda的%util 99.80%→ 这块盘已经满负荷几乎没有空闲。await 86.50ms→ 每次 IO 平均要等 86ms机械盘正常 20msSSD 5ms慢了 4 倍以上。w/s 2412、wkB/s 98240≈96MB/s→ 是猛烈的写不是读。aqu-sz 22.40→ 平均 22 个 IO 在排队说明生产速度 磁盘消费速度越堵越多。对比sdb%util 才 0.1%完全空闲 →瓶颈就锁定在 sda系统盘的写。没有iostat先装yum install -y sysstat或apt install -y sysstat。只看当前快照用iostat -x加个1就是每秒动态刷新方便观察趋势。一眼结论系统盘 sda 在遭受持续高写入单盘被打满。三、iotop 找凶手进程实拍知道盘在忙下一步找是哪个进程在写$ iotop -oP # -o 只看有 IO 的-P 只显示进程不显示线程 PID PRIO USER DISK READ DISK WRITE COMMAND 2231 be/4 mysql 0.00 B/s 92.31 MB/s mysqld 8842 be/4 app 0.00 B/s 38.74 MB/s python /opt/app/log_shipper.py两个嫌疑犯立刻浮现mysqldPID 2231写92 MB/s是主力。python log_shipperPID 8842写38 MB/s也不正常。没装iotop用pidstat兜底见下节两者看到的是同一批进程。四、pidstat -d 1 精确定位每个进程的读写速率iotop是实时面板pidstat更适合抓持续速率和历史比对$ pidstat -d 1 22:01:03 UID PID kB_rd/s kB_wr/s kB_ccwr/s Command 22:01:04 997 2231 0.00 88412.00 0.00 mysqld 22:01:04 1000 8842 0.00 38120.00 0.00 pythonkB_wr/s就是每秒写多少 KB。两个进程合计 ≈126 MB/s和第二步iostat看到的 96~98 MB/s 量级吻合差额是其它零散写正常。确认无误重点查这两个。五、到底在写哪个文件 / 目录找到 PID顺藤摸瓜定位具体文件。对 mysqld2231cat/proc/2231/io# 看累计读写总量# write_bytes: 584231321600 ≈ 544 GB 累计写增长飞快lsof-p2231|grepREG# 看它打开了哪些普通文件# mysqld 2231 mysql DEL REG 8,0 0 /var/lib/mysql/orders/#sql-tmp-2231.ibd→ 是一个MySQL 临时表文件在疯狂落盘#sql-tmp-*.ibd是CREATE TEMPORARY TABLE/ 排序用临时文件。对 python8842ls-l/proc/8842/fd|head# - /var/log/app/access.log (w)du-sh/var/log/app/access.log# 28G /var/log/app/access.log ← 单文件 28GB→ 应用把 DEBUG 日志全量写出且没做日志轮转单文件已经 28GB。进阶定位可选想精确到哪个文件被谁写可用fatrace全系统文件访问追踪或给auditd加规则。日常排障上面三步足够。六、归因为什么这两个在狂写mysqld 的根因——一条报表 SQL 没走索引MySQL 在磁盘上建临时表做排序-- 慢查询日志里抓到的原罪SELECT*FROMorders oJOINorder_items iONo.idi.order_idWHEREo.statusPAIDORDERBYo.created_atDESCLIMIT100;-- 缺 o.status 的联合索引 → 全表扫描 filesort临时表落盘python 的根因——日志级别开成 DEBUG 无轮转高峰期每秒上千条请求每条都写一行 DEBUGlogrotate没配这个路径文件无限增长。两个叠加把系统盘写满、写烂。七、止血 根治带命令分阶段第一步先止血恢复业务5 分钟内# 1. 先把失控的日志进程降权 / 停掉它最容易先解决ionice-c3-p8842# 降到空闲IO 优先级不影响别人# 或直接停服务 清空那个 28G 文件清空而非 rm避免 inode 抖动systemctl stop app-log-shipper truncate-s0/var/log/app/access.log# 2. 紧急给 MySQL 临时表换个快的地方内存盘先缓解mysqlSET GLOBALtmpdir/dev/shm;# 临时排序改到 tmpfs不再落系统盘第二步验证恢复$ iostat -x 1 sda r/s w/s rkB/s wkB/s aqu-sz await %util sda 2.0 180 8.0 7200 0.80 3.10 18.40%util从 99.8% 降到 18.4%await从 86ms 降到 3ms ——盘活过来了load 也会在几分钟内回落。第三步根治对症处理别留隐患-- MySQL补联合索引让那条 SQL 不再落盘ALTERTABLEordersADDINDEXidx_status_created(status,created_at);# 日志调成 INFO 级别 补 logrotate# /etc/logrotate.d/app-log/var/log/app/*.log{daily missingok rotate30compress delaycompress copytruncate}# 应用日志级别改为 INFO改配置后 reload八、六大常见元凶速查表定位到进程后对照下表快速归因元凶典型现象快速验证处理日志疯写某.log几 GB 级增长du -sh /var/log/* | sort -rh调日志级别 补logrotate慢 SQL / 全表扫mysqld 写高、slow log一堆SHOW PROCESSLIST 慢日志加索引、优化 SQL、tmpdir改 tmpfs备份 / 同步撞车固定时段周期性卡crontab -l看排程挪到凌晨、rsync --bwlimit限速swap 抖动随机小 IO、内存吃紧free -h看 swap 占用加内存、调小vm.swappinessRAID 卡写策略退化写性能断崖、无声megacli看 BBU/写策略修 RAID 电池恢复 WriteBack云盘突发积分耗尽周期性卡顿、平时正常看云监控 IOPS 积分换高 IOPS 云盘 / 升规格九、避坑清单都是踩过的❌只看df不看 IO磁盘没满 ≠ 磁盘不忙空间和繁忙度是两码事。❌%wa高就 reboot重启治标不治本根因还在几分钟后又堵。❌误判成 CPU 问题load 高但%us低加 CPU 没用是 IO 在等。❌云盘突发陷阱平时没事跑批时积分耗尽被限流表现为周期性卡顿。❌忽略 RAID 卡写策略WriteThrough 模式下写性能可能只有 WriteBack 的 1/10且无声无息。✅一键初筛脚本排障开头直接跑10 秒出关键结论echo load/wa ;uptime;top-bn1|head-3echo 磁盘繁忙 ;iostat-x12|awkNR1 /^[a-z]/echo 进程IO ;pidstat-d12|awkNR1 /[0-9]/十、小结标准化排查顺序背下来就能用top看%wa确认 IO 瓶颈 →iostat -x看哪块盘忙 →iotop/pidstat找凶手进程 →/proc/PID/fdlsof定位文件 → 对照元凶速查表归因 → 先ionice/truncate/tmpdir止血再补索引/轮转根治。把这套流程固化下来磁盘 IO 类告警基本能在半小时内从卡死追到真凶比盲目重启强太多。进阶要追某个文件被谁以多快速度读写可上biosnoop/biotopbpftrace 工具集要测盘的真实性能上限用fio跑随机读写基准。生产慎用建议先在测试机熟悉。本文为原创技术分享转载请注明出处。更多 Linux 运维实战干货欢迎在 CSDN 关注我。