Linux系统磁盘I/O瓶颈排查:iostat、iotop与bcc-tools工具链详解

数据库响应变慢、应用卡顿,往往是磁盘I/O在拖后腿。本文系统梳理从系统级监控iostat到进程级定位iotop,再到内核级动态追踪bcc-tools的完整排查链路,结合真实场景说明各工具的适用边界、核心参数判读与联合使用技巧,帮助运维人员快速定位I/O瓶颈源头。

Linux系统磁盘I/O瓶颈排查:iostat、iotop与bcc-tools工具链详解
封面图:ZuCDN · ZuCDN 原创

数据库查询从毫秒级退化到秒级,Web应用请求超时率突然上升,日志里反复出现“I/O wait飙高”——这类场景下,最先要排查的就是磁盘I/O。Linux内核提供了丰富的观测手段,但工具如果孤立使用,容易只见树木不见森林。本文以 iostat → iotop → bcc-tools 为排查链路,讲清楚每个工具看什么、怎么看、什么时候换下一个工具。

预备知识:读懂磁盘I/O的核心指标

在动手敲命令之前,先统一几个关键术语。iostat输出的 %util 并不是磁盘利用率,而是设备忙于服务请求的时间占比(接近100%意味着设备一直有未完成的请求,但不一定达到硬件极限)。await 是平均I/O请求经过队列等待+处理的总耗时(单位毫秒),而 svctm 仅代表处理时间。SSD的await若超过10ms基本可以判定异常,HDD则因转速不同容忍值差异大。IOPS吞吐量 需要结合随机/顺序读写场景分析。理解这些基础,才能从工具输出中提取有效信息。

iostat:系统级I/O监控的第一站

常用命令与输出解读

iostat是sysstat包的一部分,直接安装即可。生产环境中建议开启持续监控模式:iostat -x 1 10 每秒输出一次扩展统计,共10次。-x 显示rrqm/s、wrqm/s、r/s、w/s、rkB/s、wkB/s、avgrq-sz、avgqu-sz、await、r_await、w_await、svctm、%util。注意 r_awaitw_await 分读/写延迟,比单纯的await更有诊断价值。

如何判断I/O瓶颈

把关注的几个指标组合起来看:

  • %util 接近100%avgqu-sz 显著大于1 → 设备队列积压,大概率是瓶颈所在。
  • await 明显高于 svctm 的2-3倍以上 → 大部分时间花在排队等待,说明磁盘压力大或后端链路拥塞。
  • 对于SSD,如果 await > 20ms 且iops未达到官方标称值 → 可能是固件问题、驱动bug或硬件降速。
  • 单块磁盘同时跑大量小随机I/O和顺序I/O时,iostat会看到 avgrq-sz 忽高忽低,这不是瓶颈,而是负载特性。

iostat的优势是 零开销,适合长期巡检和故障时刻第一时间查看。但它只能告诉你“这设备忙”,无法回答“哪个进程在捣乱”。

iotop:按进程定位I/O消耗者

安装与基本用法

iotop基于内核taskstats接口,需要root权限。直接运行 iotop -oP,-o只显示活跃进程,-P按进程而不是线程显示。输出包含进程PID、优先级、磁盘读写速率、I/O百分比以及命令字段。

识别罪魁祸首

在iostat确认某块磁盘压力大之后,运行iotop可以立刻看到哪个进程正在大量读写磁盘。例如日志进程频繁刷盘导致%util高,或数据库进程在批量数据导出导致吞吐量突增。iotop还能观察到 I/O优先级,通过ionice调整可以临时缓解争抢。

iotop的限制在于它只能看到 进程粒度的I/O统计,而且默认不记录历史。当I/O峰值一闪而过时,iotop抓不到。另外,现代内核使用blkio cgroup限制I/O时,iotop读到的是cgroup聚合后的值,可能掩盖具体进程。

bcc-tools:深入内核栈的动态追踪

bcc-tools是什么

BCC(BPF Compiler Collection)是一套用BPF(Berkeley Packet Filter)重写的动态追踪工具集,可以在生产环境安全地探测内核/用户态事件,无需加载内核模块或修改代码。安装bcc-tools后(Ubuntu/Debian: apt install bpfcc-tools,RHEL/CentOS: yum install bcc-tools),工具名前缀通常带bpfcc-或直接可用tcptracer等。

针对磁盘I/O的核心工具

  • biotop:类似iotop但基于内核块层事件,能按进程和磁盘设备显示I/O活动,延迟更高精度。运行 biotop -C 清除历史累积,-d 5 指定刷新间隔。可以同时看到进程的读写延迟分布。
  • biosnoop:跟踪每个I/O请求的提交到完成全过程,打印时间戳、进程PID、设备、扇区、大小、延迟。是定位“哪个I/O卡住了”的利器。例如发现一个300MB的写请求延迟500ms,可能就是它阻塞了后续所有小请求。
  • filetop:按文件维度展示读写速率和次数。结合iotop找到的进程PID,进一步看该进程在读写哪些文件。例如数据库进程疯狂读写redo log,可以用filetop确认具体文件路径。
  • trace:通用动态探针。如果想追踪某个内核函数如blk_start_request被哪些进程调用,trace 'blk_start_request "dev %d" arg1' 即开。

bcc-tools的适用场景

当iostat和iotop已经精确指出“是某进程在大量写磁盘”但还无法解释“为什么写这么慢”时,bcc工具能解剖到内核I/O栈的每一层:块层队列、调度器、驱动、硬件中断。例如 biolatency 可以绘制I/O延迟直方图,区分是大多数请求都慢还是少量异常请求拖累平均值。如果发现延迟分布出现双峰,一个峰值在微秒级(正常SSD),另一个在百毫秒级,可以怀疑存在 磁盘内部垃圾回收硬件热节流 事件。

工具链联合使用实战场景

场景假设:Web应用慢查询

故障前现象:Nginx日志显示上游响应时间从20ms攀升到800ms,负载均衡报警。运维登机后步骤如下:

  1. iostat -x 1 3 看到 sdb%util=95%await=45mssvctm=8ms,读为主,rkB/s约50MB/s。确认磁盘I/O是瓶颈。
  2. iotop -oP 发现 mysqld 进程读速率40MB/s,写忽略不计。锁定数据库进程。
  3. 进一步用 biosnoop 跟踪MySQL对sdb的I/O:看到大量128KB的顺序读请求,延迟60-80ms,偶尔有一个4KB的小读延迟300ms。这种 “顺序读+偶尔卡顿” 模式通常指向 全表扫描与索引查找混合,且存储设备可能是HDD+SSD混合配置。
  4. filetop -C ‘mysqld’ 发现读集中在 /var/lib/mysql/db1/users.ibd。查询数据库慢查询日志确认确实有缺少索引的语句。
  5. 添加索引后,iostat显示%util降到30%,应用响应恢复正常。

如果没有biosnoop,只根据iostat和iotop可能会误判为磁盘性能不足而盲目升级硬件,而实际是SQL问题。这就是工具链逐层深入的价值。

注意事项与回滚

安全使用bcc-tools

BPF程序本身是安全的热插拔,但某些工具如果设置过高的采样频率(如biosnoop -d 10的间隔太小)或追踪范围过大(trace不加过滤),会增加CPU上下文切换。生产环境建议先用 -c 限制追踪单一进程,或使用 --ebpf 查看生成的BPF代码确认无危险操作。

如何验证修复效果

调整后,不要只看iostat%util下降,还要观察应用延迟是否恢复、数据库慢查询日志是否减少。用同样的工具再次采集数据对比:iostat的await是否回归正常区间,biosnoop的延迟分布峰谷是否变窄。

回滚方案

如果调优导致异常(例如盲目调整I/O调度器导致写放大),临时方案为 重启恢复调度器默认值(通过echo mq-deadline > /sys/block/sdb/queue/scheduler),或使用之前的sysfs备份。大范围使用bcc-tools时,先写一个简单的shell脚本记录改动,在测试环境验证再应用。

总结

iostat负责宏观视野,iotop定位进程,bcc-tools解剖微观延迟。三个工具协同使用,能覆盖从设备到文件再到内核调度的全链路。掌握这种排查思路,比死记硬背命令更有用——当你下次遇到 iowait 飙高时,就知道该从哪里开始敲第一行命令。

延伸阅读