linux磁盘IO性能测试应看哪些指标,避免只盯吞吐量
面向IT运维工程师,介绍Linux磁盘IO测试中吞吐量、IOPS、延迟和队列深度的判断方法,说明fio与iostat的使用边界,并提醒通过多轮复测避免单次结果误判。

先确定测试目标:吞吐量不是唯一答案
做 linux 磁盘IO性能测试前,先明确业务最关心什么:是大文件读写速度、数据库随机访问能力,还是高峰期请求延迟是否稳定。只看吞吐量很容易误判,因为吞吐高不代表业务响应快,尤其是数据库、缓存落盘、日志写入这类小块随机IO场景。
一次有参考价值的磁盘IO测试,至少要同时观察四类指标:吞吐量、IOPS、延迟和队列深度。吞吐量回答“单位时间能搬多少数据”,IOPS回答“单位时间能处理多少次IO请求”,延迟回答“单个IO请求等多久”,队列深度回答“系统为了达到这个结果堆了多少未完成请求”。这几个指标要放在同一个测试条件下看,才有判断意义。
需要先说明边界:fio、iostat等工具可以帮助构造压力和观察结果,但测试结果会受到磁盘类型、RAID策略、文件系统、内核缓存、挂载参数、业务负载、虚拟化层、存储网络等因素影响。不要用一次测试结果直接给硬件或业务下结论。
明确吞吐、IOPS、延迟分别适合看什么
不同业务对磁盘IO的敏感点不同。测试前先把业务模型拆清楚,否则很容易拿顺序读写结果去判断数据库性能。
| 指标 | 关注点 | 更适合的场景 | 常见误区 |
|---|---|---|---|
| 吞吐量 | 每秒读写的数据量,常见单位为 MB/s、GB/s | 大文件上传下载、备份、镜像分发、视频文件处理 | 顺序吞吐高,不代表随机小IO快 |
| IOPS | 每秒完成的IO次数 | 数据库、KV存储、虚拟机磁盘、小文件读写 | 只看IOPS不看延迟,可能忽略排队变长 |
| 延迟 | 单次IO从提交到完成的耗时 | 交易系统、数据库查询、日志同步写入、接口响应 | 平均延迟正常,P99延迟可能已经很差 |
| 队列深度 | 同时挂起的IO请求数量 | 判断是否靠堆积请求换性能 | 队列越深不一定越好,可能只是把等待隐藏了 |
吞吐量和IOPS之间有基本关系:
吞吐量 = IOPS × 单次IO大小
例如,同样是较高吞吐,如果块大小是1MB,可能只需要较少IOPS;如果块大小是4KB,就需要大量IOPS。数据库常见的随机4KB、8KB、16KB IO,和备份任务的1MB顺序IO,不应该放在同一个维度比较。
延迟需要重点看分位数,而不是只看平均值。平均延迟会掩盖抖动。线上业务经常不是被平均值拖垮,而是被P95、P99、P99.9这类尾部延迟影响。
测试环境要先固定,避免结果前后不可比
在Linux上做磁盘IO测试,建议先记录基础环境。后续复测、扩容、迁移或排障时,才能判断变化来自哪里。
可以先查看磁盘、文件系统和挂载信息:
lsblk -o NAME,TYPE,SIZE,MODEL,ROTA,MOUNTPOINT,FSTYPE
df -hT
mount | grep -E 'ext4|xfs|btrfs'
uname -a
如果是NVMe盘,可以查看设备信息:
nvme list
如果系统未安装相关工具,可按发行版安装。以下命令仅作为常见示例,执行前先确认系统版本和软件源可用。
Debian / Ubuntu:
sudo apt update
sudo apt install -y fio sysstat nvme-cli
RHEL / Rocky Linux / AlmaLinux:
sudo dnf install -y fio sysstat nvme-cli
测试前还需要确认几个前置条件:
- 测试目录所在分区空间充足,测试文件大小应大于内存可用缓存,避免结果主要来自页缓存。
- 尽量在非业务高峰执行测试,或者在隔离环境中测试,避免影响线上服务。
- 不建议直接对生产裸盘做写入测试;如果必须对块设备测试,需要确认数据已备份、设备未挂载、风险可接受。
- 虚拟机环境下,结果还会受到宿主机、云平台限速、存储池负载影响,不能等同于物理盘极限性能。
fio的direct=1通常用于绕过操作系统页缓存,让测试更接近磁盘或存储本身。但这并不代表完全绕过所有缓存,例如磁盘控制器缓存、RAID缓存、虚拟化存储缓存仍可能影响结果。
使用fio构造不同IO模型
fio不是“跑一个命令看分数”的工具。它的价值在于模拟不同读写模式,并输出吞吐、IOPS、延迟、队列等信息。测试时应根据业务类型分别设计场景。
下面示例使用文件测试方式,相比直接写块设备更安全。请将/mnt/test替换为实际测试目录,并确认该目录位于要测试的磁盘或文件系统上。
顺序读写:观察大文件吞吐能力
顺序写入测试示例:
fio --name=seq-write \
--directory=/mnt/test \
--filename=fio-seq-write.dat \
--size=10G \
--rw=write \
--bs=1M \
--ioengine=libaio \
--direct=1 \
--iodepth=16 \
--numjobs=1 \
--runtime=300 \
--time_based \
--group_reporting
顺序读取测试示例:
fio --name=seq-read \
--directory=/mnt/test \
--filename=fio-seq-read.dat \
--size=10G \
--rw=read \
--bs=1M \
--ioengine=libaio \
--direct=1 \
--iodepth=16 \
--numjobs=1 \
--runtime=300 \
--time_based \
--group_reporting
顺序读写更适合评估备份、归档、镜像拉取、大文件处理等场景。这里重点看bw,也要顺带观察延迟是否异常升高。如果吞吐看起来不错,但延迟分位数很高,说明该盘在高压力下可能不适合延迟敏感业务。
随机读写:观察小块IO能力和延迟
随机读测试示例:
fio --name=rand-read \
--directory=/mnt/test \
--filename=fio-rand-read.dat \
--size=10G \
--rw=randread \
--bs=4k \
--ioengine=libaio \
--direct=1 \
--iodepth=32 \
--numjobs=4 \
--runtime=300 \
--time_based \
--randrepeat=0 \
--group_reporting
随机写测试示例:
fio --name=rand-write \
--directory=/mnt/test \
--filename=fio-rand-write.dat \
--size=10G \
--rw=randwrite \
--bs=4k \
--ioengine=libaio \
--direct=1 \
--iodepth=32 \
--numjobs=4 \
--runtime=300 \
--time_based \
--randrepeat=0 \
--group_reporting
随机IO更接近数据库、小文件、虚拟机系统盘等场景。这里不能只看IOPS,还要看clat的平均值和分位数。IOPS升高但P99延迟同步升高,通常意味着系统正在靠排队换取吞吐。
混合读写:更接近业务负载
很多业务不是纯读或纯写,可以用rwmixread指定读比例。例如70%读、30%写:
fio --name=mixed-rw \
--directory=/mnt/test \
--filename=fio-mixed-rw.dat \
--size=10G \
--rw=randrw \
--rwmixread=70 \
--bs=8k \
--ioengine=libaio \
--direct=1 \
--iodepth=32 \
--numjobs=4 \
--runtime=300 \
--time_based \
--randrepeat=0 \
--group_reporting
混合测试更适合观察读写互相影响。部分存储在纯读时表现稳定,但一旦写入比例增加,延迟会明显波动。数据库、消息队列、日志系统尤其要关注这一点。
运行测试时同步观察系统层指标
fio输出的是压测任务视角,系统层还需要用iostat观察磁盘设备是否已经饱和。
另开一个终端执行:
iostat -x 1
重点关注这些字段:
| 字段 | 含义 | 观察方式 |
|---|---|---|
| r/s、w/s | 每秒读写请求数 | 可与fio的IOPS大致对照 |
| rkB/s、wkB/s | 每秒读写数据量 | 可与fio的带宽大致对照 |
| await | IO平均等待时间,包括排队和服务时间 | 持续升高通常表示延迟压力增加 |
| aqu-sz | 平均队列长度 | 队列持续变长要结合延迟判断 |
| %util | 设备忙碌比例 | 接近100%不一定就是故障,但说明设备长期繁忙 |
不同sysstat版本字段名称可能略有差异,例如旧版本可能显示avgqu-sz。另外,%util在机械盘上较容易理解,在SSD、NVMe、多队列设备上不能单独作为饱和判断依据。更可靠的方式是结合吞吐、IOPS、延迟分位数和队列变化一起看。
如果需要更方便地后续分析,可以让fio输出JSON:
fio --name=rand-read \
--directory=/mnt/test \
--filename=fio-rand-read-json.dat \
--size=10G \
--rw=randread \
--bs=4k \
--ioengine=libaio \
--direct=1 \
--iodepth=32 \
--numjobs=4 \
--runtime=300 \
--time_based \
--randrepeat=0 \
--group_reporting \
--output-format=json \
--output=fio-rand-read.json
JSON结果更适合保留历史记录,对比不同内核、不同文件系统、不同挂载参数或不同存储策略下的变化。
结果解释:把四个指标放在一起看
fio结果中常见字段包括bw、iops、slat、clat、lat。一般排查时更关注完成延迟clat以及总延迟lat。
bw:吞吐量,适合判断大块顺序读写能力。iops:每秒IO次数,适合判断小块随机访问能力。slat:提交延迟,表示fio提交IO花费的时间。clat:完成延迟,表示IO提交后到完成的时间,通常更有参考价值。lat:总延迟,一般可理解为提交到完成的整体耗时。percentile:延迟分位数,例如95%、99%、99.9%。
判断时可以按以下顺序看:
- 先看测试模型是否匹配业务,例如块大小、读写比例、随机/顺序、并发数是否合理。
- 再看吞吐或IOPS是否达到业务需求,而不是只看是否“越高越好”。
- 接着看平均延迟和P95、P99延迟是否在业务可接受范围内。
- 最后看队列深度和系统层
aqu-sz是否持续变高,判断性能是否靠堆积请求换来。
一个常见误判是:提高iodepth后,吞吐和IOPS上升,于是认为磁盘更快了。实际上,队列深度增加意味着同时压入更多请求,单个请求可能等待更久。对于离线备份任务,这可能可以接受;对于数据库交易请求,尾部延迟升高可能直接影响接口响应。
另一个误判是:只跑顺序写就判断整盘性能。顺序写通常更容易跑出好看的吞吐,但它不能代表随机读写、同步写、fsync、元数据操作、小文件创建删除等业务行为。
fio测试有边界,不能替代真实业务压测
fio可以稳定构造IO模式,但它仍然是合成测试。它不能完整模拟数据库事务、索引命中、应用锁等待、网络调用、对象存储协议、虚拟化调度等复杂行为。
需要特别注意这些边界:
direct=1能减少Linux页缓存影响,但不能代表应用真实读写路径一定如此。- 文件系统测试和裸块设备测试结果不同,文件系统元数据、日志模式、挂载参数都会影响结果。
- 小测试文件可能被缓存命中,导致结果偏高。
- 测试时间过短可能只看到缓存、预热或瞬时突发能力,看不到稳定状态。
- SSD、NVMe在长时间写入后可能出现垃圾回收、磨损均衡、SLC缓存耗尽等状态变化。
- RAID卡缓存、存储阵列缓存、云平台缓存可能改变延迟分布。
- 在线业务负载会与fio争抢IO资源,测试结果和业务体验会互相影响。
如果测试对象是生产环境,建议先做只读测试或低压力测试,确认影响范围后再逐步增加压力。写入测试尤其要谨慎,不要在不确认路径和设备的情况下对关键目录或块设备执行。
避免单次测试下结论:复测要控制变量
磁盘IO性能测试的结果不是孤立数字。复测时至少要固定这些条件:
- 同一台服务器、同一块盘或同一存储卷。
- 同一测试目录、文件系统、挂载参数。
- 同一fio版本、内核版本、测试命令。
- 相同
bs、rw、iodepth、numjobs、runtime、size。 - 尽量相似的业务负载和系统后台任务状态。
- 每个场景至少执行多轮,观察波动范围,而不是只取最好的一次。
更合理的记录方式是为每类业务建立基准。例如:
| 业务类型 | 建议测试模型 | 重点指标 |
|---|---|---|
| 备份与归档 | 顺序读写,较大块,例如1M | 吞吐量、稳定性 |
| 数据库读多写少 | 随机读为主,4K或8K,混合少量写 | IOPS、P95/P99延迟 |
| 日志写入 | 顺序写或同步写模型 | 写延迟、抖动、fsync影响 |
| 虚拟机磁盘 | 随机读写混合,多并发 | IOPS、尾部延迟、队列深度 |
| 批处理任务 | 顺序读写与随机读写组合 | 吞吐、对其他业务影响 |
如果测试结果出现明显变化,不要立即判断为磁盘故障。先检查是否有后台任务、备份、日志归档、数据库刷脏页、RAID重建、文件系统检查、虚拟化宿主机负载变化。可以配合以下命令观察系统状态:
top
vmstat 1
iostat -x 1
pidstat -d 1
其中pidstat -d 1可以帮助查看哪些进程正在产生磁盘IO。若系统未安装,可通过sysstat软件包提供。
复测时建议保留fio命令、输出文件、测试时间、系统负载、磁盘型号或卷信息。以后遇到“业务变慢”“迁移后性能下降”“扩容后效果不明显”时,历史基准比单次跑分更有价值。
执行前后的安全检查和复测条件
在Linux磁盘IO性能测试中,真正有价值的不是某个漂亮数字,而是同一测试目标下吞吐、IOPS、延迟、队列深度之间是否平衡。大文件业务可以优先看吞吐;数据库和虚拟机磁盘要重点看IOPS与P99延迟;高并发场景还要确认性能是否依赖过高队列深度。
建议每次测试前后按以下清单核对:
- 确认测试目录不是业务关键目录,写测试不会覆盖重要文件。
- 确认测试文件大小足够,避免主要命中系统缓存。
- 确认测试命令中的
rw、bs、iodepth、numjobs符合业务模型。 - 测试时同步记录
iostat -x 1,不要只保存fio末尾结果。 - 至少复测多轮,并记录波动范围。
- 如果要对比两次结果,只改变一个变量,例如文件系统、挂载参数或磁盘类型,避免多个变量同时变化。
当复测条件无法保持一致时,结果只能作为当前环境下的参考值,不能直接用于承诺线上业务性能。磁盘类型、缓存策略和实际负载一旦变化,linux磁盘IO性能测试的吞吐、IOPS、延迟和队列深度都可能随之变化。