排查Linux服务器性能问题时,磁盘IO往往是首要怀疑对象。然而,许多工程师一看到监控面板上飘红的磁盘利用率,就急于扩容硬件或优化代码,结果可能徒劳无功。关键在于,你观察到的“高IO”究竟是真实的硬件瓶颈,还是由不当应用行为引发的假象?

Linux如何查看磁盘IO利用率:别只盯着%util,先判断是否真瓶颈
一个常见的误区是将%util(设备利用率)直接等同于磁盘“忙不过来”。实际上,这个指标仅表示在采样周期内,设备有IO请求的时间百分比。这意味着,一块高性能的SSD即使长期保持100%的利用率,只要请求能被快速处理,系统响应依然可以非常流畅。相反,一块机械硬盘(HDD)如果%util持续超过80%,就需要引起高度警惕。
要准确判断IO是否成为系统瓶颈,必须结合await(平均每次IO请求的等待时间,单位毫秒)和r/s/w/s(每秒读写次数)进行综合分析:
- 场景一:真实瓶颈:当
%util ≈ 100%,同时await值显著升高(SSD通常>20ms,HDD>50ms),这基本可以断定磁盘IO已成为性能瓶颈,请求堆积导致了延迟上升。 - 场景二:虚假饱和:如果
%util很高,但await始终很低(例如<10ms),这通常意味着大量短小、高频的请求占满了设备的队列深度,但每个请求都能被快速处理。问题的根源可能不在磁盘本身,而在于应用逻辑,例如一个循环grep大目录的脚本。 - 场景三:隐藏问题:业务感知卡顿,但
%util显示很低。此时,问题可能出在文件系统层(如ext4日志写入阻塞)、内存页缓存不足,或者IO被其他低优先级进程抢占(可用iotop -oP命令验证)。
最直接的检查命令是:iostat -x 1 3。运行后,请重点关注输出中的Device、%util、await、r/s、w/s这几列关键数据。
sar -d 检查磁盘IO:参数组合决定你看到的是“快照”还是“趋势”
如果说iostat是为磁盘拍摄一张“实时快照”,那么sar -d的价值就在于它能带你“回顾历史”,分析性能变化的长期趋势。不过,它的能力依赖于sysstat工具包的后台数据收集服务(默认每10分钟记录一次)。如果该服务未启用,sar -d要么只能查询当天有限的数据,要么可能完全无法获取历史记录。
使用前,务必先确认服务状态:systemctl is-active sysstat。如果显示inactive,需要立即启用它:systemctl enable --now sysstat。
掌握几个关键的命令组合,能帮助你高效定位问题:
- 查看今天每10分钟的汇总数据:
sar -d -f /var/log/sa/sa$(date +%d) - 查看指定历史时间段(例如昨天下午2点到4点):
sar -d -s 14:00:00 -e 16:00:00 -f /var/log/sa/sa$(date -d "yesterday" +%d) - 默认输出中设备名可能被缩写,加上
-p参数可以显示更友好的名称(如sda、nvme0n1)。
这里有一个重要细节:sar -d输出中的rd_sec/s和wr_sec/s单位是“扇区/秒”(通常1扇区=512字节),并非直接的字节/秒。计算实际带宽时,需要乘以512再除以1024两次,才能得到MB/s。
为什么sar -d 有时显示DEV为空或全是0?
遇到sar -d输出异常,先别急于怀疑命令语法。这通常是底层数据源出现了问题:
- 数据文件问题:
/var/log/sa/saXX文件可能被误清空,或权限设置不正确(应为root:root,644)。 - 版本兼容性:过旧的
sysstat版本(如低于12.0)可能无法正确识别NVMe或多路径设备,导致sar -d解析失败,整行数据被跳过。 - 逻辑设备未采集:对于LVM逻辑卷或加密卷(设备名如
dm-0),默认配置下sar可能不采集其数据。需要在/etc/sysconfig/sysstat(或类似路径)配置文件中,修改DISKSTATS项来包含它们。 - 时间范围跨天:如果查询时间横跨了午夜(例如从23:59到00:05),
sar不会自动拼接两天的数据文件,需要分两次查询后手动合并分析。
快速验证数据收集是否正常的一个方法是:手动触发一次采集sa1 -A,然后立刻查询最近一分钟的数据:sar -d -s $(date -d '1 minute ago' +%H:%M:%S) -e $(date +%H:%M:%S)。如果这次有输出,就说明是历史数据缺失,而非命令本身的问题。
替代方案:当 sar -d 不可用时,直接读取 /proc/diskstats
当sar历史数据不可用,或者你需要编写监控脚本进行秒级诊断时,/proc/diskstats这个内核接口是你的终极武器。它提供了最原始的计数器,没有采集延迟。
这个文件的每一行代表一个块设备,字段顺序固定,其中几个关键字段是:
- 第6列(
r sectors):累计读取的扇区总数。 - 第10列(
w sectors):累计写入的扇区总数。 - 第14列(
io_ticks):设备处于忙碌状态的总毫秒数,这正是计算%util的基础。
通过间隔采样,可以自行计算出实时的带宽和利用率。下面是一个简单的两秒间隔采样示例脚本:
read1=$(awk '$3=="vdb"{print $6}' /proc/diskstats)
write1=$(awk '$3=="vdb"{print $10}' /proc/diskstats)
time1=$(awk '$3=="vdb"{print $14}' /proc/diskstats)
sleep 2
read2=$(awk '$3=="vdb"{print $6}' /proc/diskstats)
write2=$(awk '$3=="vdb"{print $10}' /proc/diskstats)
time2=$(awk '$3=="vdb"{print $14}' /proc/diskstats)
echo "read MB/s: $(( (read2-read1)*512/1024/1024/2 ))"
echo "util%: $(( (time2-time1)/2 ))"
需要注意的是,这种方法需要你自行处理设备名的精确匹配(vdb、nvme0n1、dm-0的写法不同),并且无法直接得到await这类衍生指标——这些还是得依靠iostat或iotop。
归根结底,磁盘IO性能分析的难点,往往不在于记住几个命令参数,而在于准确区分“设备物理性能已达上限”和“应用程序滥用IO资源”。同一个疯狂扫描日志目录的grep进程,在SSD上可能只是让队列满负荷运转,在机械硬盘上却足以拖垮整个系统的响应速度。因此,在盯着那些数字下结论之前,不妨先问自己:我到底是在优化存储硬件,还是在追查那个捣乱的定时任务?
