4. 性能监控工具:使用 iostat、vmstat、sar 等工具监控 I/O 性能
4.1 核心原理:从“黑盒”到“白盒”的监控分层
当存储 I/O 出现性能瓶颈时,我们首先需要回答三个问题:系统整体是否繁忙?瓶颈在哪个设备?I/O 请求在哪个阶段排队? 性能监控工具的价值,正是将内核中的 I/O 子系统状态以可读的指标呈现出来。Linux 下最常用的三款工具——iostat、vmstat、sar——分别从设备层、系统层和历史趋势三个维度提供观测视角。
理解这些工具的输出,需要先掌握 I/O 路径上的关键队列模型。一次读请求从应用程序发起,经过页缓存(Page Cache)、块设备层(Block Layer)的调度队列,最终到达磁盘控制器。每个环节都可能成为瓶颈:vmstat 的 b 列反映进程因等待 I/O 而阻塞的数量;iostat 的 %util 反映设备处理请求的繁忙程度;sar 则能回溯历史负载,帮助判断瓶颈是瞬时尖峰还是持续累积。
上图展示了三款工具在 I/O 路径上的观测位置。实际定位时,建议先 vmstat 看整体,再 iostat 看设备,最后用 sar 回溯历史,形成完整的证据链。
4.2 方法流程:三工具协同定位 I/O 瓶颈
4.2.1 第一步:用 vmstat 快速判断系统是否“卡在 I/O”
vmstat 提供的是系统级视图。执行以下命令,每 2 秒采样一次,共采样 5 次:
vmstat 2 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
2 1 0 8123456 12345 4567890 0 0 12 34 567 890 5 3 88 4 0
3 2 0 8123000 12345 4567890 0 0 4567 8901 2345 6789 12 15 45 28 0
4 3 0 8118000 12345 4567890 0 0 8901 12345 3456 9012 10 20 30 40 0
关键列解读:
- b(阻塞进程数):持续大于 2 且伴随
wa升高,说明进程在等待 I/O 完成。 - bi/bo(块设备每秒接收/发送的块数):bi 高表示读压力大,bo 高表示写压力大。单位是块(1 块 = 512 字节 / 1024 字节,取决于系统)。
- wa(CPU 等待 I/O 时间百分比):持续超过 30% 时,I/O 已成为主要瓶颈。
- si/so(交换分区换入换出):如果持续非零,说明内存不足导致频繁换页,I/O 压力被进一步放大。
b 列接近 0 且 wa 很低,但应用依然缓慢,则瓶颈可能在 CPU 或锁竞争,而非 I/O。此时应转向 top 或 pidstat 进一步排查。
4.2.2 第二步:用 iostat 定位具体设备与延迟构成
确认系统存在 I/O 瓶颈后,使用 iostat -x 查看每个设备的详细指标:
iostat -x 2 3
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sda 0.00 12.00 0.00 145.00 0.00 4567.00 63.00 0.80 5.50 0.00 5.50 0.50 7.25
sdb 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
dm-0 0.00 0.00 0.00 145.00 0.00 4567.00 63.00 0.80 5.50 0.00 5.50 0.50 7.25
核心指标含义:
- r/s, w/s:每秒读写请求数(IOPS)。
- rkB/s, wkB/s:每秒读写吞吐量。
- await:I/O 请求从进入队列到完成处理的平均等待时间(毫秒)。这是最直观的延迟指标。
- r_await / w_await:区分读和写的平均等待时间。若读等待远高于写,可能是读缓存不足或磁盘寻道开销大。
- svctm:设备实际处理请求的平均时间(不含排队)。注意:在 NVMe 或 SSD 上该值可能失真,参考意义有限。
- %util:设备繁忙百分比。接近 100% 表示设备已饱和,但要注意 SSD 并行处理能力较强,%util 高不一定意味着延迟不可接受。
%util 就下结论。例如,一个 RAID 阵列由 8 块盘组成,单块盘 %util 为 30%,但整体阵列可能已接近吞吐上限。应结合 await 和 avgqu-sz(平均队列长度)综合判断。若 await 远大于 svctm,说明排队时间过长,设备处理能力不足。
4.2.3 第三步:用 sar 回溯历史与捕捉瞬时尖峰
sar 的优势在于可以记录历史数据,适合事后分析。首先确认系统已开启 sysstat 服务,然后使用:
# 查看今天每 10 分钟的设备 I/O 统计
sar -d -f /var/log/sysstat/sa$(date +%d) | head -30
# 实时查看每 2 秒的全局 I/O 情况
sar -b 2 5
# 查看内存与交换分区
sar -r 2 5
sar -d 输出示例:
12:00:01 AM DEV tps rd_sec/s wr_sec/s avgrq-sz avgqu-sz await svctm %util
12:10:01 AM sda 12.5 0.00 512.00 41.00 0.01 0.80 0.40 0.50
12:20:01 AM sda 145.0 0.00 45670.00 63.00 0.80 5.50 0.50 7.25
12:30:01 AM sda 89.3 0.00 23456.00 52.00 0.45 3.20 0.45 4.00
通过对比不同时间点的数据,可以判断 I/O 负载是持续高位还是周期性波动,从而关联到定时任务、业务高峰等外部因素。
4.3 案例实战:定位数据库写入延迟问题
某在线交易系统反馈“订单提交变慢”,DBA 怀疑是存储问题。我们按以下流程排查:
- vmstat 快速检查:发现
b列持续为 3-4,wa达到 35%,确认存在 I/O 等待。 - iostat -x 定位设备:看到
sdb(数据库数据盘)的w/s高达 800,w_await为 45ms,而svctm仅 2ms。说明大量请求在排队,磁盘处理不过来。 - sar -d 回溯:查看过去 2 小时的数据,发现从 14:00 开始
wr_sec/s从 2000KB/s 飙升到 50MB/s,与业务方确认是促销活动导致写入量激增。 - 进一步分析:使用
iostat -x -k 1观察avgqu-sz(平均队列长度)持续超过 10,确认磁盘队列深度过高。
最终结论:磁盘写入吞吐达到上限,且 I/O 调度器合并效率不足。优化措施包括:将数据库日志盘与数据盘分离、调整 I/O 调度器为 none(NVMe 场景)、增加应用层批量写入。
4.4 误区与复盘:监控工具使用中的常见陷阱
| 误区 | 表现 | 正确做法 |
|---|---|---|
| 只看 %util 判断磁盘饱和 | %util 100% 但延迟很低(SSD 场景) | 结合 await 和 avgqu-sz,SSD 应关注延迟而非利用率 |
| 忽略页缓存命中率 | iostat 显示高读吞吐,但实际是缓存未命中 | 先用 free 查看 cache 大小,或用 sar -B 查看页缓存命中率 |
| 采样间隔过短或过长 | 间隔 1 秒可能捕捉到瞬时尖峰造成误判;间隔 10 分钟可能遗漏关键波动 | 先用 2-5 秒间隔观察 1 分钟,再根据业务周期调整 |
| 未区分读写延迟 | await 高但不知道是读还是写导致 | 查看 r_await 和 w_await,分别优化 |
| 忽略设备映射关系 | 看到 dm-0 高负载,但不知道对应哪块物理盘 | 使用 lsblk 或 dmsetup ls 确认映射关系 |
%util,误以为磁盘已满负荷。后来通过 w_await 与 svctm 的差值发现是排队延迟,而非设备处理能力不足。进一步用 sar 回溯才找到写入量突增的根因。监控工具不是孤立使用的,vmstat 判断方向,iostat 定位设备,sar 还原时间线,三者配合才能形成完整证据链。此外,所有工具都只能反映内核视角的 I/O 状态,应用层的日志、慢查询等同样重要,需要交叉验证。
最后,建议在日常运维中养成定期采集 sar 数据的习惯(默认 sysstat 已开启),并设置阈值告警:当 await 超过 20ms(机械盘)或 5ms(SSD)时触发通知。这样在故障发生时,你已经有历史基线可供对比,能更快定位是“突然变慢”还是“持续劣化”。