数据库查询从毫秒级退化到秒级,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_await 和 w_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,负载均衡报警。运维登机后步骤如下:
- iostat -x 1 3 看到 sdb 的 %util=95%,await=45ms,svctm=8ms,读为主,rkB/s约50MB/s。确认磁盘I/O是瓶颈。
- iotop -oP 发现 mysqld 进程读速率40MB/s,写忽略不计。锁定数据库进程。
- 进一步用 biosnoop 跟踪MySQL对sdb的I/O:看到大量128KB的顺序读请求,延迟60-80ms,偶尔有一个4KB的小读延迟300ms。这种 “顺序读+偶尔卡顿” 模式通常指向 全表扫描与索引查找混合,且存储设备可能是HDD+SSD混合配置。
- 用 filetop -C ‘mysqld’ 发现读集中在 /var/lib/mysql/db1/users.ibd。查询数据库慢查询日志确认确实有缺少索引的语句。
- 添加索引后,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 飙高时,就知道该从哪里开始敲第一行命令。
延伸阅读
