本文要点
- 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
看结果时盯住两处:
- 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
结果: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
结果解读:
- 读带宽
5455KiB/s、写带宽5450KiB/s,按 4K 块折算约 2726 IOPS(10 秒内完成 13638 次读 + 13627 次写) Disk stats里util=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/randrw | I/O 类型:顺序/随机,读/写/混合 |
--bs=<size> | 块大小,如 1M、4k;顺序用大块测带宽,随机用小块测 IOPS |
--size=<size> | 测试文件大小 |
--runtime=<秒> | 测试时长,常配合 --time_based 用(跑满时长,文件不够就循环) |
--numjobs=<n> | 并行 job 数,模拟多进程并发 |
--iodepth=<n> | 队列深度,必须配合异步引擎才生效 |
--ioengine=libaio/io_uring/sync | I/O 引擎,异步引擎才支持真正的队列深度 |
--rwmixwrite=<百分比> | randrw 模式下写所占比例 |
--direct=1 | 绕过页缓存直接读写磁盘,测真实性能 |
--group_reporting | 多 job 时汇总输出 |
--output-format=json | JSON 输出,方便脚本解析与 CI 对比 |
--direct=1 建议做正式基准时加上:默认 fio 会经过页缓存,读测试可能命中缓存造成虚高,直接读写才能拿到磁盘真实水平(本文为贴近日常使用场景未加)。
小结
fio 用法一句话:--rw 定方向、--bs 定块大小、--runtime 定时长,然后读 Run status 里的 bw/iops 和 Disk stats 里的 util。判断磁盘是否背锅,牢记两条:顺序 IO 看 MB/s,随机 IO 看 IOPS;util 接近 100% 且性能上不去,就是磁盘瓶颈。本文这块云盘顺序写 136 MiB/s、顺序读 106 MiB/s、随机 4K 混合约 2726 IOPS、util 全程 90% 以上——一块典型的低配云盘,选型、对比或排障时都可以拿这几个数字做基准。
评论 (0)
暂无评论,快来抢沙发吧!