暗色模式

fio 磁盘基准测试:从顺序读写到随机 IOPS 与队列深度

技术教程
2026-09-04
9
0
本文要点
  • fio 是磁盘性能基准的标准工具,衡量两大指标:带宽(大块顺序 IO,MB/s)与 IOPS(小块随机 IO,次/秒)
  • 本文实测一块低配云盘:顺序写 136 MiB/s、顺序读 106 MiB/s,读写都只有百 MB 级且读反而低于写,典型云盘画像
  • 随机 4K 读写各半约 2726 IOPS,磁盘 util(利用率)全程 93~95%——util 接近 100% 说明磁盘本身就是瓶颈
  • 坑:fio 默认同步引擎下 --iodepth=32 不生效,IO depths 始终是 1=100%;须换 --ioengine=libaio 队列深度才真正堆起来
  • 判断磁盘是否背锅:util 接近 100% 且 IOPS/带宽上不去 → 磁盘饱和;util 低而性能差 → 先去查 CPU、进程与网络

fio 是什么:测磁盘的带宽与 IOPS 两把尺子

评估磁盘性能和排查网络一样,不能只靠"感觉快"。磁盘有两个正交的指标,用错尺子会得出完全错误的结论:

  • 带宽(Bandwidth):大块顺序 IO 的吞吐,单位 MB/s,对应复制大文件、备份、数据库全量扫描
  • IOPS(Input/Output Per Second):小块随机 IO 的每秒次数,对应数据库按主键查询、日志追加、大量小文件读写

fio(Flexible I/O Tester)就是测这两把尺子的标准工具,由内核调度器作者 Jens Axboe 维护,几乎所有发行版都收录。安装与版本检查:

apt install -y fio
fio --version

本文实测环境是一台阿里云 Ubuntu 24.04 的 demo 机(fio 3.36),磁盘是云厂商提供的虚拟云盘 /dev/vda。测试命令统一在 /tmp 目录下运行,避免在 home 目录留下测试文件。

顺序写测试:先摸清持续写入带宽

顺序写模拟"持续往磁盘写大文件"的场景。--rw=write 指定纯写、--bs=1M 用 1MB 大块测带宽、--size=512M 限制测试文件为 512MB、--runtime=10 跑满 10 秒(配合 --time_based,文件写不完就循环)、--group_reporting 让多 job 汇总输出:

fio --name=seq_write --rw=write --bs=1M --size=512M --runtime=10 --time_based --group_reporting

顺序写测试:136 MiB/s,10 秒写入 1358 MiB

看结果时盯住两处:

  • Run status group 的汇总行WRITE: bw=136MiB/s (142MB/s)io=1358MiB (1424MB)——10 秒写入了 1358 MiB,持续写带宽 136 MiB/s
  • Disk stats 的 util 列util=94.86%——磁盘利用率接近 100%,说明磁盘一直在满负荷工作。带宽上不去不是软件问题,是这块盘本身就到头了

136 MiB/s 的持续写带宽,对照企业级 NVMe SSD 动辄 3~5 GB/s,量级差了二三十倍——低配云盘的顺序写水平大概就在这个区间。

顺序读测试:读不一定比写快

顺序读把 --rw 换成 read,其余参数保持一致:

fio --name=seq_read --rw=read --bs=1M --size=512M --runtime=10 --time_based --group_reporting

顺序读测试:106 MiB/s,10 秒读取 1065 MiB

结果:READ: bw=106MiB/s (112MB/s),10 秒读取 1065 MiB,util=90.85%

这里有个反直觉的现象:读带宽(106 MiB/s)反而低于写带宽(136 MiB/s)。本地 SSD 通常是读远快于写,但云盘受共享存储、I/O 调度和计费档位影响,读写性能可能不对称——这正是必须实测而不是凭经验猜的原因。而带宽不高往往只是冰山一角,随机小 IO 的表现更难看,见下一节。

随机 4K 混合读写:模拟真实业务的 IOPS

数据库查询、日志系统、Web 应用的文件读写,大多是 4K~16K 的小块随机 IO。这时看带宽没有意义,要看 IOPS--rw=randrw 做随机混合读写、--rwmixwrite=50 让读写各占 50%、--bs=4k 用 4K 小块:

fio --name=rand_rw --rw=randrw --rwmixwrite=50 --bs=4k --size=512M --iodepth=32 --runtime=10 --time_based --group_reporting

随机 4K 混合读写:读 5455 KiB/s、写 5450 KiB/s,约 2726 IOPS

结果解读:

  • 读带宽 5455KiB/s、写带宽 5450KiB/s,按 4K 块折算约 2726 IOPS(10 秒内完成 13638 次读 + 13627 次写)
  • Disk statsutil=93.58%,又是接近饱和——磁盘是绝对瓶颈
  • 注意 IO depths: 1=100.0% 这一行:明明指定了 --iodepth=32,为什么提交深度一直是 1?

队列深度的正确打开方式:异步引擎

--iodepth(队列深度)表示"允许同时挂在磁盘上等待完成的请求数"。上一节的结果里 IO depths 一直是 1=100.0%,原因是我们没指定 --ioengine——fio 默认用同步 I/O 引擎(sync),一次只能发出一个请求、等它完成再发下一个,队列深度被死死限制在 1,--iodepth=32 形同虚设。

要让队列深度真正生效,必须换成异步引擎,例如 libaio

fio --name=async_test --rw=randread --bs=4k --size=128M --iodepth=32 --ioengine=libaio --runtime=5 --time_based --group_reporting

同样的 --iodepth=32,这次 IO depths 变成 32=99.5%——队列真正堆到了 32,请求在磁盘里排队处理。但注意 IOPS 依然只有约 1368,和同步引擎的结果几乎一样。

这恰好是判断瓶颈类型的关键技巧:换异步引擎后 IOPS 纹丝不动、util 依旧接近 100%,说明这块盘的随机 IO 能力本身就封顶了,瓶颈在硬件而非软件队列;如果换引擎后 IOPS 明显上涨,才说明之前是驱动或队列设置限制住了。前者就换云盘档位或换硬件吧。

常用参数速查

参数作用
--rw=write/read/randwrite/randread/randrwI/O 类型:顺序/随机,读/写/混合
--bs=<size>块大小,如 1M4k;顺序用大块测带宽,随机用小块测 IOPS
--size=<size>测试文件大小
--runtime=<秒>测试时长,常配合 --time_based 用(跑满时长,文件不够就循环)
--numjobs=<n>并行 job 数,模拟多进程并发
--iodepth=<n>队列深度,必须配合异步引擎才生效
--ioengine=libaio/io_uring/syncI/O 引擎,异步引擎才支持真正的队列深度
--rwmixwrite=<百分比>randrw 模式下写所占比例
--direct=1绕过页缓存直接读写磁盘,测真实性能
--group_reporting多 job 时汇总输出
--output-format=jsonJSON 输出,方便脚本解析与 CI 对比

--direct=1 建议做正式基准时加上:默认 fio 会经过页缓存,读测试可能命中缓存造成虚高,直接读写才能拿到磁盘真实水平(本文为贴近日常使用场景未加)。

小结

fio 用法一句话:--rw 定方向、--bs 定块大小、--runtime 定时长,然后读 Run status 里的 bw/iops 和 Disk stats 里的 util。判断磁盘是否背锅,牢记两条:顺序 IO 看 MB/s,随机 IO 看 IOPSutil 接近 100% 且性能上不去,就是磁盘瓶颈。本文这块云盘顺序写 136 MiB/s、顺序读 106 MiB/s、随机 4K 混合约 2726 IOPS、util 全程 90% 以上——一块典型的低配云盘,选型、对比或排障时都可以拿这几个数字做基准。

参考资料

发表评论

暂无评论,快来抢沙发吧!