在 Linux 服务器上排查性能问题时,磁盘 I/O 是一个很常见的方向。比如系统响应变慢、数据库查询变慢、日志写入延迟、程序偶尔卡住,或者 CPU 看起来不高但业务处理速度明显下降,这些情况都可能和磁盘 I/O 有关。

iostat 是一个非常常用的 Linux 性能分析命令,可以用来查看 CPU 使用情况和磁盘设备的读写情况。它适合快速判断磁盘是否繁忙、读写请求是否堆积、I/O 延迟是否过高,以及当前负载是偏读还是偏写。

我平时比较常用的命令是:

Bash
iostat 1 -d -x -p sda

这条命令的作用是每 1 秒输出一次 sda 这块磁盘及其分区的详细 I/O 统计信息。

一、命令参数说明 #

这条命令可以拆开看:

Bash
iostat 1 -d -x -p sda

其中:

TEXT
1

表示每隔 1 秒刷新一次输出。如果不指定次数,它会持续输出。

TEXT
-d

表示只显示设备使用情况,不显示 CPU 统计信息。

TEXT
-x

表示显示扩展统计信息。磁盘排查时一般都会加上这个参数,因为普通输出里的信息太少,不够判断 I/O 延迟和队列情况。

TEXT
-p sda

表示显示 sda 这块磁盘以及它下面的分区信息。比如可能会看到 sdasda1sda2 等。

如果想看所有磁盘和分区,可以使用:

Bash
iostat -d -x -p ALL 1

如果是 NVMe 硬盘,设备名通常不是 sda,而是类似:

TEXT
nvme0n1

这时可以改成:

Bash
iostat 1 -d -x -p nvme0n1

二、先注意第一屏输出 #

使用 iostat 时有一个细节需要注意:第一屏输出通常是系统启动以来的平均值,并不一定代表当前状态。官方手册也说明,第一份报告默认统计的是系统启动以来的数据,后续报告才是两次输出间隔内的数据。([Man7][1])

所以排查实时问题时,不要只看第一屏。一般可以让它连续跑几秒,多观察后面的数据。

例如:

Bash
iostat -d -x -p sda 1 10

这个命令表示每 1 秒输出一次,总共输出 10 次。

如果想跳过第一屏启动以来的统计,可以使用:

Bash
iostat -y -d -x -p sda 1

其中 -y 的作用就是省略第一份自系统启动以来的报告。

三、常见返回字段解释 #

不同版本的 sysstat 输出字段可能略有差异,但常见字段大致如下。

参数 含义
Device 设备名,例如 sdasda1nvme0n1
r/s 每秒完成的读请求数,已经包含合并后的结果
w/s 每秒完成的写请求数,已经包含合并后的结果
rkB/s 每秒读取的数据量,单位通常是 kB
wkB/s 每秒写入的数据量,单位通常是 kB
rrqm/s 每秒合并的读请求数量
wrqm/s 每秒合并的写请求数量
%rrqm 读请求在发送到设备前被合并的百分比
%wrqm 写请求在发送到设备前被合并的百分比
r_await 平均每次读请求耗时,单位毫秒,包括排队时间和服务时间
w_await 平均每次写请求耗时,单位毫秒,包括排队时间和服务时间
aqu-sz 平均 I/O 队列长度
rareq-sz 平均每个读请求大小,单位通常是 kB
wareq-sz 平均每个写请求大小,单位通常是 kB
await 所有 I/O 请求的平均等待时间,包含读写请求
%util 设备有 I/O 请求的时间占比,可以理解为设备繁忙程度

其中 awaitr_awaitw_await 都是毫秒级指标,并且包含请求排队时间和实际处理时间;aqu-sz 是平均队列长度;%util 表示有 I/O 请求发给设备的时间占比。官方手册也提醒,对于传统串行处理请求的设备,%util 接近 100% 往往意味着设备接近饱和;但对于 RAID、现代 SSD 等可并行处理请求的设备,不能只靠这个数字判断性能上限。([Man7][1])

四、几个最关键的指标 #

虽然 iostat -x 输出字段很多,但真正排查问题时,不需要每个字段都盯着看。一般先看下面几个。

1. %util:磁盘忙不忙 #

%util 可以理解为设备处理 I/O 的繁忙程度。

如果 %util 长时间接近 100%,说明这块磁盘一直有 I/O 请求在处理。对于机械硬盘或者传统块设备,这通常意味着磁盘压力比较大。

但对于 SSD、NVMe、RAID 阵列来说,%util 接近 100% 不一定代表性能已经完全到顶。因为这类设备可以并行处理多个请求,不能简单用机械硬盘的思路判断。

所以 %util 要结合 awaitaqu-sz 一起看。

2. await / r_await / w_await:请求慢不慢 #

await 表示 I/O 请求从提交到完成的平均时间,包含排队和实际执行时间。

如果 await 很高,说明应用提交的 I/O 请求等了比较久。

如果是:

TEXT
r_await 高

说明读请求延迟高,可能影响数据库查询、文件读取、程序加载等。

如果是:

TEXT
w_await 高

说明写请求延迟高,可能影响日志写入、数据库事务、文件保存等。

排查时要注意看是读慢还是写慢,不要只看一个总的 await

3. aqu-sz:请求有没有排队 #

aqu-sz 表示平均 I/O 队列长度。这个值越高,说明等待处理的请求越多。

如果 %util 高、await 高、aqu-sz 也高,通常说明磁盘压力已经比较明显,请求开始排队。

如果 %util 高但 await 不高,说明磁盘很忙,但请求处理速度还能跟上。

如果 await 高但 %util 不高,就要进一步排查是不是底层存储、虚拟化环境、网络盘、阵列、文件系统或其他原因导致延迟异常。

4. r/s、w/s、rkB/s、wkB/s:读写量有多大 #

r/sw/s 是每秒读写请求数量。

rkB/swkB/s 是每秒读写数据量。

这两组指标要一起看。

如果 r/sw/s 很高,但 rkB/swkB/s 不高,可能是大量小 I/O。

如果 r/sw/s 不高,但 rkB/swkB/s 很高,可能是少量大块连续读写。

大量小 I/O 对机械硬盘影响很明显,对数据库、日志、缓存类业务也很常见;大块连续 I/O 则更多出现在备份、拷贝、压缩、视频处理、批量导入导出等场景。

五、如何快速判断磁盘是否成为瓶颈 #

可以按下面思路看:

第一,看 %util 是否长期很高。

如果 %util 长时间接近 100%,说明设备一直处于忙碌状态。

第二,看 await 是否明显升高。

如果 await 也高,说明请求不只是多,而且处理慢,应用层很可能会感觉到卡顿。

第三,看 aqu-sz 是否增加。

如果队列长度越来越高,说明请求堆积,磁盘处理速度跟不上业务提交速度。

第四,看是读压力还是写压力。

通过 r/srkB/sr_await 判断读压力。 通过 w/swkB/sw_await 判断写压力。

第五,结合业务场景判断。

例如:

  • 数据库查询慢,重点看读延迟 r_await
  • 日志写入慢,重点看写延迟 w_await
  • 文件复制慢,重点看吞吐量 rkB/swkB/s
  • 系统整体卡顿,重点看 %utilawaitaqu-sz
  • 虚拟机磁盘慢,还要考虑宿主机和底层存储

六、一个简单的观察示例 #

假设看到类似情况:

TEXT
Device     r/s     w/s   rkB/s   wkB/s   r_await   w_await   aqu-sz   %util
sda        5.00  450.00  120.00  9000.00    2.00     85.00     8.50    98.00

这时可以大致判断:

  • w/s 很高,说明写请求很多
  • wkB/s 明显高于 rkB/s,说明主要是写入压力
  • w_await 达到 85ms,写请求延迟较高
  • aqu-sz 为 8.50,说明有请求排队
  • %util 为 98%,设备非常忙

这种情况下,磁盘写入很可能已经成为瓶颈。接下来就应该继续查是谁在写磁盘。

可以配合使用:

Bash
iotop

或者:

Bash
pidstat -d 1

查看具体进程的磁盘读写情况。

七、常用命令整理 #

查看某块磁盘的详细 I/O:

Bash
iostat -d -x -p sda 1

查看所有磁盘和分区:

Bash
iostat -d -x -p ALL 1

只看设备,不看 CPU:

Bash
iostat -d 1

显示扩展信息:

Bash
iostat -x 1

跳过第一屏启动以来的平均值:

Bash
iostat -y -d -x -p sda 1

连续输出 10 次:

Bash
iostat -d -x -p sda 1 10

查看 NVMe 磁盘:

Bash
iostat -d -x -p nvme0n1 1

八、关于 svctm 字段 #

有些旧版本 iostat 输出中会看到 svctm 字段,表示平均每次设备 I/O 操作的服务时间。

不过在较新的 sysstat 输出里,这个字段已经不一定出现。实际排查时,也不建议过度依赖 svctm。现在更常用的判断方式是看:

TEXT
await
r_await
w_await
aqu-sz
%util

这些指标组合起来,比单独看 svctm 更有参考价值。

九、总结 #

iostat 是 Linux 下排查磁盘 I/O 问题非常实用的命令。常用命令可以记成:

Bash
iostat -y -d -x -p sda 1

其中:

  • -d 表示只看磁盘设备
  • -x 表示显示扩展统计信息
  • -p sda 表示查看 sda 及其分区
  • 1 表示每秒刷新一次
  • -y 表示跳过第一屏启动以来的平均值

实际排查时,重点关注:

TEXT
%util
await
r_await
w_await
aqu-sz
r/s
w/s
rkB/s
wkB/s

如果 %util 长时间很高,同时 awaitaqu-sz 也升高,通常说明磁盘 I/O 压力比较明显。接下来可以结合 iotoppidstat -d、应用日志和业务访问情况,继续定位到底是哪个进程或业务造成了磁盘压力。