Linux磁盘IO性能分析:iostat、iotop、fio实战

系统卡顿排查到最后一层,十有八九是磁盘 IO。CPU 不忙、内存也够,但 wa 就是下不去,load 莫名其妙地高------很可能有一堆进程卡在 D 状态等磁盘。磁盘是整台机器里最慢的部件,也是最容易被后台任务拖垮的。这一篇用 iostat、iotop、pidstat -d、fio 四个工具,教你看懂磁盘的四个核心指标,并定位到具体是哪个进程在制造 IO。

一、先搞懂四个核心指标

看磁盘性能,无论用什么工具,都是围绕这四个数字转:

指标 含义 单位
IOPS 每秒完成多少次 IO 请求 次/秒
吞吐量(带宽) 每秒读写多少数据 MB/s
延迟(await) 每个 IO 平均耗时(含排队) ms
队列深度(aqu-sz) 排队等待处理的 IO 数量 个

它们的关系,用生活比喻最好懂:

IOPS 是「收银台每秒服务几个人」,吞吐是「每秒卖出多少货」,延迟是「每个顾客平均等多久」,队列深度是「队伍里排了多少人」。

小文件、随机读写 场景(数据库、日志)看 IOPS + 延迟 ;大文件、顺序读写 场景(备份、视频)看 吞吐。别混。

二、iostat:磁盘全景统计

iostat 属于 sysstat,是最常用的磁盘性能工具。

安装

复制代码
sudo apt install sysstat -y       # Ubuntu
sudo dnf install sysstat -y       # Rocky/CentOS

语法格式

复制代码
iostat [选项] [间隔] [次数]

常用参数

参数 说明
-d 只看磁盘,不显示 CPU
-x 显示扩展统计(含 await、%util),最常用
-m 以 MB/s 显示吞吐
-k 以 KB/s 显示(默认)
-p 显示分区级
1 5 每秒采样,共 5 次

示例与预期输出

复制代码
iostat -dxm 1 3

预期输出:

复制代码
Device   r/s    rMB/s   rrqm/s  %rrqm  r_await  rareq-sz   w/s    wMB/s  wrqm/s  %wrqm  w_await  wareq-sz  aqu-sz  %util
sda      2.50    0.10    0.00    0.00    1.20   40.00   120.00  15.30   8.00   6.25    8.40   130.00    0.98   95.20
sdb      0.00    0.00    0.00    0.00    0.00    0.00     0.50   0.02   0.00   0.00    0.80    36.00    0.00    0.10

重点列解读:

列 含义 判断信号
r/s w/s 每秒读/写请求数 即 IOPS
rMB/s wMB/s 读/写吞吐 看带宽用
r_await w_await 读/写平均延迟(ms) 关键!高于设备基线就是有问题
aqu-sz 平均队列深度 持续 > 1 说明排队严重
%util 设备忙碌时间百分比 接近 100% 说明饱和
rareq-sz wareq-sz 平均每次请求大小(KB) 判断是随机小 IO 还是顺序大 IO

⚠️ 关于 %util 的经典误区

%util 接近 100% 常被当作「磁盘满了」的铁证,但对 SSD/NVMe 它非常具有误导性------SSD 内部能并行处理多个请求,%util 100% 时性能可能还很充沛。

判断磁盘是否真饱和,更可靠的是 await(延迟)和 aqu-sz(队列深度)范疇:

  • await 明显高于设备正常水平 → 有压力
  • aqu-sz 持续大于 1 → 请求在排队

单看 %util,机械盘还算靠谱,SSD 上要结合延迟一起看。

三、iotop:看到底是谁在 IO

iostat 告诉你是「哪块盘」忙,但不知道「哪个进程」在搞。iotop 补上这一环,类似 top 但按 IO 排序。

安装

复制代码
sudo apt install iotop -y       # Ubuntu
sudo dnf install iotop -y       # Rocky/CentOS

语法格式与常用参数

复制代码
sudo iotop [选项]
参数 说明
-o 只显示正在进行 IO 的进程
-b 批处理模式,适合写脚本
-n N 采样 N 次后退出
-P 只显示进程,不显示线程
-k 用 KB/s 显示
-a 显示累计 IO,而非实时速率

示例与预期输出

复制代码
sudo iotop -oP

预期输出:

复制代码
Total DISK READ:       1.20 M/s | Total DISK WRITE:     15.30 M/s
  PID  PRIO  USER     DISK READ  DISK WRITE   SWAPIN  IO>   COMMAND
 1234 be/4  mysql       0.00 B/s   8.50 M/s     0.00%  0.30%  mysqld
 5678 be/4  root      800.0 K/s   6.00 M/s     0.00%  0.80%  rsync --daemon

-o 过滤掉零 IO 的进程,-P 只看进程,输出干净。第一行的 Total 是全局读写速率。IO> 列是该进程等待 IO 的时间占比,越高越卡。

注意:iotop 需要 root 权限(要读 /proc/*/io),普通用户会报 CONFIG_TASK_IO_ACCOUNTING 或权限相关错误。

四、pidstat -d:无交互的进程级 IO

iotop 是交互式,不适合记录。要做数据采集,用 pidstat -d(同属 sysstat)。

复制代码
pidstat -d 1 5

UID   PID  kB_rd/s  kB_wr/s  kB_ccwr/s  iodelay  Command
root  1234     0.00  8704.00      0.00      120   mysqld
root  5678   800.00  6144.00      0.00       85   rsync

其中 iodelay(较新内核)是进程被 IO 阻塞的时钟节拍数,是比速率更能反映「被 IO 拖累」的指标。

五、fio:磁盘基准测试

上面三个是「看现状」,fio 是「测能力」------磁盘到底能跑多少 IOPS、多少带宽、延迟多高。换机器、调优前后对比,都靠它。

安装

复制代码
sudo apt install fio -y       # Ubuntu
sudo dnf install fio -y       # Rocky/CentOS

语法格式

复制代码
fio [选项] 作业文件

常用参数

参数 说明
--name=xxx 作业名
--rw=randread 随机读;read/write/randwrite/rw 等
--bs=4k 块大小
--iodepth=32 IO 队列深度
--numjobs=4 并发作业数
--size=1G 每个作业读写数据量
--runtime=60 运行 60 秒
--time_based 到时间才停
--direct=1 绕过 page cache,测试真实磁盘
--filename=/dev/sdb 目标设备或文件

示例与预期输出

测 4K 随机读的 IOPS(数据库典型场景):

复制代码
sudo fio --name=randread --ioengine=libaio --direct=1 \
  --rw=randread --bs=4k --iodepth=32 --numjobs=4 \
  --size=1G --runtime=60 --time_based --group_reporting

预期输出(节选):

复制代码
  read: IOPS=98.5k, BW=385MiB/s (403MB/s)
    lat (usec): min=8, max=2000, avg=32.40
  iops        : min= 95400, max=101200, avg=98520

测顺序写带宽(日志/备份场景):

复制代码
sudo fio --name=seqwrite --ioengine=libaio --direct=1 \
  --rw=write --bs=1M --iodepth=16 --size=1G --runtime=30 --time_based

  write: IOPS=520, BW=520MiB/s

⚠️ fio 使用禁忌

绝对不要对生产盘直接跑写测试。 --filename=/dev/sdb 会覆盖数据。测试前:

  • 用空文件 或专门的测试盘/测试分区
  • 或在文件系统上用 --filename=/tmp/testfile(非裸设备)并确认路径安全

--direct=1 绕过缓存,结果更真实;不带它测的是「缓存速度」,没有参考价值。

六、一张表学会看懂 iostat

把 iostat -dx 的输出和判断标准对应起来:

现象 可能原因
w/s 高、wareq-sz 小(几 KB) 大量随机小写,日志/数据库常见
rMB/s 高、rareq-sz 大(几百 KB+) 顺序大读,备份/视频
await 远高于设备基线 磁盘压力大或队列深
aqu-sz 持续 > 1 请求排队,磁盘响应不过来
%util 100% 但 await 很低 SSD 正常,吞吐很可能没满
%util 100% 且 await 很高 真饱和,是瓶颈

七、⚠️ 常见错误

  1. 拿 %util 当唯一标准 。SSD 上 %util 100% 不代表瓶颈,要看 await 和吞吐是否达到设备上限。
  2. 测磁盘不带 --direct=1。测出来的是 page cache 速度(几个 GB/s),跟真实磁盘无关。
  3. 在生产盘上跑 fio 写测试。直接覆盖数据,事故级别。测试要用专门介质。
  4. 忽视 D 状态进程 。ps 里一堆 D、load 高但 CPU 闲,这就是 IO 瓶颈的典型信号,去查 iotop。
  5. 只盯平均延迟 。await 是平均值,可能被大量快请求拉低。要结合分布看(iostat 看不了分布,需 bpftrace/blktrace 或 fio 的延迟百分位)。
  6. 忽略文件系统层 。磁盘快不代表文件系统快,ext4 的 journal、XFS 的分配策略都会影响实际性能。

八、原理探究:机械盘 vs SSD,以及 IO 调度器

机械盘(HDD)的物理限制

机械盘有一个转动的盘片和一个移动的磁头。每次读写要 寻道(seek) 把磁头移到目标柱面,再 **旋转(rotational latency)**等到扇区转到磁头下。这两步是纯机械动作,毫秒级。

这决定了 HDD:

  • 随机 IO 极慢(每次都要寻道,100~200 IOPS 到头)
  • 顺序 IO 快得多(磁头不用大幅移动,可达 100+ MB/s)

所以 HDD 上,把随机访问改成顺序访问是最大优化点(比如 LSM 树 vs B+ 树、追加写日志)。

SSD 的特点

SSD 没有机械动作,靠闪存芯片,随机和顺序差距没 HDD 那么大,天生擅长随机 IO(几万到几十万 IOPS)。但有两个特性要注意:

  • 写放大:闪存以「块」为单位擦除,改写要读-改-写,实际写入量可能大于请求量。
  • 寿命(TBW):闪存有擦写次数上限,fio 压测要适可而止。

IO 调度器

内核在块设备层有调度器,决定 IO 请求怎么合并、排序、下发:

调度器 适用 特点
none(noop) SSD/NVMe 不排队不排序,直接下发,SSD 自己有内部调度
mq-deadline 通用 保证请求在期限内处理,防饿死
kyber 高性能 SSD 按读/写/丢弃分别限流
bfq 桌面/低延迟 按进程分配带宽,交互友好

查看和设置:

复制代码
# 查看当前设备调度器
cat /sys/block/sda/queue/scheduler

# 临时改成 none(SSD 推荐)
echo none | sudo tee /sys/block/sda/queue/scheduler

# 永久:写 udev 规则或内核参数 elevator=

SSD 上通常用 none/mq-deadline ,把调度交给硬件;机械盘可用 bfq 或 mq-deadline 优化交互。

九、IO 排查实操流程

复制代码
# 1. 系统整体 IO 概况
iostat -dxm 1 5

# 2. 找制造 IO 的进程
sudo iotop -oP

# 3. 记录进程级 IO(可写脚本)
pidstat -d 1 5

# 4. 看是否有进程卡在 D 状态
ps -eo state,pid,cmd | grep "^D"

# 5. 查看脏页回写压力
grep -E "Dirty|Writeback" /proc/meminfo

# 6. 测设备真实能力(非生产盘)
sudo fio --name=t --rw=randread --bs=4k --iodelay... # 见上文

一条经验:磁盘问题里,80% 是「谁在乱写」而不是「磁盘坏了」。日志暴涨、备份撞车、数据库全表扫描、临时表落盘,这些应用层行为才是元凶。先找到那个进程,再谈优化磁盘本身。

相关推荐
可信时间戳1 小时前
原创作品如何做版权认证申请?先备材料,再挑路径
服务器·音视频·可信时间戳·权利卫士
北城笑笑1 小时前
Server 18 ,Nginx 双服务器 HTTP转HTTPS 代理实战( HTTP 地址换 HTTPS 域名 )
运维·服务器·前端·后端·nginx·http·https
I'mChloe1 小时前
不再逐台装Docker:我用Ansible Playbook批量统一服务器环境
服务器·docker·ansible
LiaoWL1231 小时前
从零开始学 Linux(一):目录结构、常用命令与 VIM 编辑器上手
linux·运维·服务器
分布式存储与RustFS1 小时前
RustFS 上生产第一步:从单机到 4 节点多盘集群(MNMD)部署实操
运维·云原生·开源·对象存储·分布式存储·s3·性能基准
for_ever_love__1 小时前
LangGraph Checkpointer:持久化、断点续跑与多轮记忆
服务器·数据库·学习·持久化·langgraph·checkpointer·断点续跑
Data analyse4561 小时前
用户路径SQL按会话起止时间聚合的方法
大数据·服务器·前端·数据库·人工智能·sql·数据分析
Lhan.zzZ1 小时前
Linux + Qt/QML:解决 QtQuick.VirtualKeyboard.Plugins 模块加载失败与环境变量配置
linux·数据库·qt
小毛驴8502 小时前
mvn help:effective-settings 与 mvn help:effective-pom
java·linux·前端