Linux 磁盘 IO 等待过高的定位方法

6次阅读

%wa高说明CPU大量时间等待IO完成,反映IO阻塞而非必然磁盘慢;需结合iostat、iotop等工具定位具体瓶颈点。

Linux 磁盘 IO 等待过高的定位方法

top 里 %wa 值高说明什么

%watop 中显示的 CPU 等待 IO 完成的时间百分比。它高 ≠ 磁盘慢,只说明有大量线程在阻塞等待 IO(比如读写文件、刷脏页、等待 NFS 响应)。真正瓶颈可能在磁盘本身,也可能在内核 IO 调度、文件系统层、甚至远程存储网络。

常见误判:看到 %wa > 30% 就断定是磁盘坏了——其实可能是某个进程反复 fsync()、日志刷盘太频繁,或 ext4 的 journal 模式配置不当。

  • %wa 高但 %sy(内核态 CPU)也同步飙升,大概率是内核路径争用(如大量小文件 write + sync)
  • %wa 高而 %us(用户态 CPU)很低,说明应用基本没在计算,纯卡在 IO 上
  • top 不区分读/写、不显示具体设备,必须配合 iostatiotop 进一步下钻

iostat -x 1 看哪些指标最关键

运行 iostat -x 1 后重点关注三列:%utilawaitsvctm(已弃用,忽略)和 r/s/w/s。其中:

  • %util 接近 100% 表示该设备几乎一直在忙,但注意:NVMe 多队列设备下这个值参考价值下降,需看 avgqu-sz(平均队列深度)是否持续 > 1
  • await 是单次 IO 平均耗时(毫秒),> 50ms 对 SATA 盘已偏高,> 10ms 对 NVMe 就值得查——但它包含排队时间,不能直接等同于磁盘响应慢
  • 对比 r_awaitw_await 可快速判断是读还是写拖慢;若 w_await 显著更高,检查 vm.dirty_ratio 是否设得过大,导致刷盘风暴

示例异常输出:

iostat -x 1
sda 0.00 21.00 0.00 689.00 0.00 7345.00 21.42 100.00 145.12 145.12 0.00

这里 await=145.12%util=100.00,且 avgqu-sz=21.42,说明请求严重积压。

用 iotop 找出吃 IO 的进程

iotop 是实时定位罪魁进程最直接的工具,但默认不显示线程级 IO(尤其 java 应用常有多个线程共用一个文件描述符)。启动时加 -P 查看进程汇总,加 -o 只显示有 IO 活动的条目,加 -a 累计 IO 量更准。

  • 注意看 IO> 列(当前瞬时写入速率)和 IO 列(累计总写入量),后者对识别“缓慢但持久”的后台任务(如 rsync、logrotate)更有用
  • 如果看到 java 进程 IO 很高,别急着 kill,先用 lsof -p PID 查它打开的文件,重点看 logs//tmpmapped files(内存映射大文件读写也会计入 IO)
  • 某些数据库(如 mysql)的 innodb_io_capacity 设置远低于磁盘实际能力,会导致大量 IO 被人为节流,此时 iotop 看到的是“被压低的 IO”,而非真实瓶颈

排查 ext4/xfs 文件系统层延迟

即使磁盘硬件正常,文件系统配置不当也会放大 IO 延迟。ext4 默认启用 barrier=1journal=ordered,在无电池保护的 RAID 卡上会强制落盘,极大拖慢写性能。

  • 检查挂载参数:mount | grep ' / '`,留意是否有 barrier=0(不推荐关)、data=writeback(降低 journal 开销,但崩溃可能丢数据)
  • 对 xfs,关注 xfs_info 输出中的 logbsizelogbufs,过小的日志缓冲区(如 logbsize=4k)会导致频繁刷日志
  • 临时验证:用 dd if=/dev/zero of=/tmp/test bs=4M count=1000 oflag=direct 测裸写速度,若远低于磁盘标称值,问题大概率在文件系统或驱动层

真正难定位的往往是混合场景:比如 postgresql 在 checkpoint 期间触发大量脏页回写,同时应用又在高频小事务提交,两者叠加让 await 突增,但单独看任一环节都“看似正常”。这时候得结合 pidstat -d 1perf record -e block:block_rq_issue,block:block_rq_complete -a sleep 10 抓块层事件链。

text=ZqhQzanResources