☰
fio磁盘性能测试实战:从部署到结果解读的完整指南
2026/10/14 15:16:05 网站建设 项目流程

1. 为什么我劝你先别急着敲fio命令

很多人第一次接触磁盘性能测试,都是因为线上服务突然变慢,怀疑是磁盘IO拖了后腿。于是搜到fio这个工具,复制一条命令跑下去,看到一堆数字就以为掌握了真相。我早期也这么干过,结果拿着错误的结果去跟存储团队对峙,最后发现是自己测试方法有问题,场面相当尴尬。

fio的全称是Flexible I/O Tester,直译过来就是“灵活IO测试器”。它的核心价值在于能模拟各种真实业务场景下的IO负载——数据库的随机读写、日志系统的顺序追加、视频转码的大块连续读写,这些都能通过参数组合精确复现。但问题也恰恰出在这里:参数太多,组合太灵活,不同参数组合出来的结果可能天差地别。你测出来磁盘能跑50万IOPS,换一组参数可能连5万都不到,两个结果都没错,但对应的是完全不同的业务场景。

这篇文章面向的是需要在Linux环境下做磁盘性能评估的运维、后端开发和系统工程师。我会从部署开始,把fio的安装、参数含义、测试模型设计、结果解读、常见误区和排查思路完整讲一遍。读完你至少能做到三件事:第一,根据业务特征设计出合理的测试方案;第二,看懂fio输出里哪些数字真正重要;第三,遇到结果异常时知道从哪几个方向排查。文章里涉及的操作步骤和参数配置都经过实际验证,你可以直接参考使用。

2. fio的部署:包管理器与源码编译怎么选

2.1 各发行版安装方式对比

fio在主流Linux发行版的官方仓库里都有,直接通过包管理器安装是最省事的方式。但不同发行版仓库里的版本差异比较大,这一点需要留意。

发行版安装命令仓库常见版本备注
CentOS 7yum install -y fio3.7左右版本偏老,部分新参数不支持
Rocky/Alma 8+dnf install -y fio3.19+版本较新,日常够用
Ubuntu 20.04apt install -y fio3.16稳定版,功能完整
Ubuntu 22.04apt install -y fio3.28推荐,支持大部分新特性
Debian 11/12apt install -y fio3.25/3.33版本较新

安装完成后用fio --version确认版本号。如果你的测试需要用到较新的参数(比如--numa_cpu_nodes、--ssdplp等),而仓库版本太老,那就需要考虑源码编译。

2.2 源码编译的适用场景与步骤

什么时候需要源码编译?我总结了几种情况:仓库版本低于3.15、需要特定编译选项(比如启用libaio以外的IO引擎)、或者需要在非主流架构上运行。编译过程本身不复杂,但依赖包容易漏装。

# 安装编译依赖 yum install -y gcc make libaio-devel zlib-devel # 或者 Ubuntu/Debian apt install -y gcc make libaio-dev zlib1g-dev # 下载源码(以3.35为例) wget https://github.com/axboe/fio/archive/refs/tags/fio-3.35.tar.gz tar -xzf fio-3.35.tar.gz cd fio-fio-3.35 # 配置与编译 ./configure make -j$(nproc) make install

编译完成后fio默认安装在/usr/local/bin/fio。这里有个容易忽略的细节:如果系统里同时存在包管理器安装的旧版本,which fio可能指向/usr/bin/fio,导致你以为在用新版本实际用的是旧的。用fio --version和which fio双重确认。

注意:源码编译时如果没装libaio-devel,configure阶段不会报错,但编译出来的fio会缺少libaio引擎,跑测试时指定--ioengine=libaio会直接报错。这个坑我踩过,排查了半天才发现是依赖缺失。

2.3 验证安装与权限确认

安装完先跑一条最简单的命令验证:

fio --name=verify --filename=/tmp/fio_test --size=64M --rw=write --bs=4k --direct=1 --runtime=10 --time_based

这条命令会在/tmp下创建一个64MB的文件做4K直接写入测试。如果报权限错误,检查当前用户对目标目录是否有写权限。如果报direct=1不支持,说明文件系统不支持O_DIRECT(比如tmpfs就不支持),换到ext4或xfs分区上测试。

另外提醒一点:测试裸盘(比如/dev/sdb)需要root权限,测试文件系统上的文件则普通用户即可。生产环境做裸盘测试前务必确认目标盘上没有数据,--filename指向错误的分区会导致数据丢失。

3. 理解fio的参数体系:从业务场景反推配置

3.1 四个核心维度决定测试模型

fio的参数有上百个,但决定测试模型本质的就四个维度:IO类型(读/写/混合)、IO大小(块大小)、IO模式(顺序/随机)、并发深度(队列深度和线程数)。把这四个维度想清楚,参数配置就完成了一大半。

IO类型由--rw控制。常见取值有read、write、randread、randwrite、randrw、rw。其中randrw和rw是混合读写,需要配合--rwmixread指定读的比例。比如数据库场景通常是randrw加--rwmixread=70,表示70%读30%写。

IO大小由--bs控制。4K对应数据库OLTP场景,8K/16K对应部分中间件,64K/128K对应大块顺序读写,1M以上对应视频流或备份场景。块大小直接决定了IOPS和带宽的换算关系:IOPS乘以块大小就是带宽。4K随机读跑出10万IOPS,换算带宽就是400MB/s左右。

IO模式由--rw中的rand前缀决定。顺序读写适合评估大文件传输和日志追加场景,随机读写适合评估数据库和虚拟化场景。这里有个常见误解:很多人觉得SSD不需要关心顺序还是随机,实际上SSD在顺序和随机下的性能差异虽然比机械盘小,但在高队列深度下依然明显。

并发深度由--iodepth和--numjobs共同决定。--iodepth是单个job的队列深度,--numjobs是并行job数量。总并发等于两者乘积(在同一个job共享文件的情况下)。机械盘队列深度超过32基本没有收益,NVMe盘可以跑到128甚至256。

3.2 常用参数速查与业务映射

下面这张表把常见业务场景和fio参数配置对应起来,可以直接参考:

业务场景rwbsiodepthnumjobs说明
MySQL OLTPrandrw16k324rwmixread=70
Redis AOFwrite4k11顺序追加
日志采集write64k162顺序写
视频转码read1M81大块顺序读
虚拟机镜像randrw4k648rwmixread=50
备份恢复write1M164大块顺序写

这张表不是标准答案,而是一个起点。实际配置需要根据你的业务压测数据调整。比如MySQL的OLTP,真实场景下块大小可能是16K,但队列深度取决于连接数和存储类型,需要逐步调整找到拐点。

3.3 时间控制与结果稳定性

--runtime和--time_based是一对搭档。只写--runtime=60,fio会在完成指定size的数据量后停止,如果size设得小可能几秒就跑完了。加上--time_based后,fio会在指定时间内持续跑,size变成循环单位。做稳定性测试和稳态性能评估时,--time_based是必须的。

--ramp_time用来跳过预热阶段。SSD在刚写入时可能因为垃圾回收或缓存机制表现出虚高的性能,跑一段时间后才进入稳态。设置--ramp_time=30可以让fio先跑30秒预热,这30秒的数据不计入最终结果。我一般建议至少设10秒,对性能波动大的盘设30秒以上。

--group_reporting在多job场景下把结果合并输出,避免每个job单独打印一大段。做多线程测试时加上这个参数,输出会清爽很多。

4. 从零设计一个可信的测试方案

4.1 明确测试目标再动手

拿到一个磁盘性能测试需求,先别急着写命令。问清楚三个问题:测什么盘(机械/SSD/NVMe/网络存储)、模拟什么业务(数据库/文件服务/虚拟化)、关注什么指标(IOPS/带宽/延迟)。这三个问题的答案直接决定参数配置。

举个例子,如果目标是评估一块NVMe盘能否支撑某数据库的峰值负载,那测试模型应该是:随机读写混合、块大小16K、读比例70%、队列深度从32逐步加到256、多job并行。如果目标是评估一块SATA SSD作为日志盘的写入能力,那模型应该是:顺序写、块大小64K、队列深度16、单job或双job。

4.2 测试文件与裸盘的取舍

测试对象可以是文件,也可以是裸盘。两者各有适用场景。

测试文件的好处是安全、灵活、不需要root权限,适合开发环境和初步评估。但文件系统本身会引入额外开销(元数据、日志、缓存),测出来的结果不完全等于裸盘性能。测试文件时建议用--direct=1绕过页缓存,否则测的是内存速度而不是磁盘速度。

测试裸盘能获得最接近硬件的性能数据,适合生产环境评估和存储选型。但裸盘测试会破坏数据,必须确保目标盘无数据。另外裸盘测试需要root权限,且不能用--direct=0(裸盘没有文件系统缓存的概念)。

提示:如果非要在生产环境做裸盘测试,建议先用lsblk和blkid确认目标盘没有挂载、没有文件系统、没有数据。我见过有人把/dev/sda当成数据盘测试,结果把系统盘写了,教训很深刻。

4.3 参数组合的逐步调优方法

一次性把所有参数设到最优是不现实的。我的做法是分步调优:先固定IO类型和块大小,从低队列深度开始跑,逐步增加队列深度,观察IOPS和延迟的变化曲线。当IOPS不再增长而延迟开始飙升时,那个拐点就是这块盘在当前场景下的最佳并发点。

具体操作上,可以用一个循环脚本自动跑多组参数:

for iodepth in 1 4 8 16 32 64 128; do fio --name=qd_test --filename=/data/testfile --size=4G \ --rw=randread --bs=4k --direct=1 --ioengine=libaio \ --iodepth=$iodepth --runtime=30 --time_based --ramp_time=10 \ --group_reporting --output-format=json \ --output=result_qd${iodepth}.json done

跑完后从JSON结果里提取IOPS和延迟数据,画成曲线就能看到拐点。这种逐步调优的方法比一次性拍脑袋设参数靠谱得多。

4.4 测试时长与数据量的平衡

测试时长太短,结果受缓存和预热影响大;测试时长太长,浪费时间且可能影响生产。我的经验是:初步评估跑30秒到1分钟,正式评估跑3到5分钟,稳定性测试跑30分钟以上。数据量方面,测试文件大小至少要是磁盘容量的两倍以上,否则可能一直在同一区域读写,测不出全盘性能。

对于SSD,还要考虑写入放大和垃圾回收的影响。如果测试写入性能,建议先对盘做一次全盘写入(--rw=write --bs=1M跑满全盘),让盘进入稳态后再测。否则测出来的可能是出厂状态的虚高性能。

5. 结果解读:哪些数字真正值得看

5.1 输出字段的含义与优先级

fio的输出信息量很大,但真正需要关注的字段就那么几个。下面按优先级排列:

字段含义关注点
iops每秒IO次数随机读写场景的核心指标
bw带宽顺序读写场景的核心指标
lat (avg)平均延迟整体响应水平
lat (p99)99分位延迟长尾延迟,比平均值更重要
clat完成延迟不含排队时间的纯IO延迟
slat提交延迟提交IO到内核的时间
cpuCPU占用评估测试本身的开销

很多人只看IOPS和带宽,忽略了延迟分布。实际上对于数据库和在线服务,p99延迟比平均IOPS更能反映用户体验。一块盘IOPS很高但p99延迟抖动大,实际业务表现可能很差。

5.2 延迟分布与长尾问题

fio的延迟统计默认输出平均值、标准差、最大值和分位数。分位数里p50、p90、p95、p99、p99.9都值得看。如果p99是平均值的5倍以上,说明存在明显的长尾延迟,可能是垃圾回收、队列拥塞或硬件问题导致的。

可以用--latency_percentiles参数自定义输出的分位数,比如--latency_percentiles=50,90,99,99.9,99.99。对于延迟敏感的业务,p99.9甚至p99.99才是真正需要关注的。

另外--latency_target和--latency_window可以设置延迟目标,fio会自动调整队列深度来满足延迟要求。这个功能在做SLA验证时很有用。

5.3 如何判断结果是否可信

拿到结果后先别急着下结论,做几个合理性检查。第一,看CPU占用。如果fio进程CPU占用接近100%,说明测试本身成了瓶颈,磁盘性能没被充分压出来。第二,看队列深度是否达到设定值。如果实际队列深度远低于设定值,说明IO提交速度跟不上。第三,看测试前后磁盘的SMART信息,确认没有异常。

还有一个简单的方法:用不同工具交叉验证。比如用dd做顺序写测试,用fio做随机读测试,如果两者结果差异巨大且无法解释,说明测试方法可能有问题。

6. 踩坑实录:那些让我重新跑测试的瞬间

6.1 页缓存导致的虚高结果

早期做文件测试时没加--direct=1,测出来顺序读带宽跑到好几GB/s,比盘的理论带宽还高。原因就是数据被页缓存了,fio读的是内存不是磁盘。加上--direct=1后结果直接掉到真实水平。这个坑很常见,尤其是测试小文件时,文件可能完全被缓存,测出来的结果毫无意义。

注意:--direct=1在部分文件系统上可能不支持,比如tmpfs、overlayfs。如果报错,换到ext4或xfs分区测试,或者用--invalidate=1在每次IO前失效缓存(但效果不如direct)。

6.2 队列深度设置不当导致的误判

有一次评估一块NVMe盘,设了--iodepth=1跑随机读,结果IOPS只有几千,差点得出“这块盘不行”的结论。后来意识到NVMe的优势在于高队列深度,改成--iodepth=128后IOPS直接冲到几十万。队列深度和存储类型强相关,机械盘低队列深度就能跑满,NVMe需要高队列深度才能发挥。

6.3 测试文件大小与磁盘容量的关系

测试文件设得太小,比如在1TB盘上只测1GB文件,fio可能一直在同一区域读写,测出来的是局部性能而非全盘性能。尤其是机械盘,内外圈性能差异明显,只测外圈会高估整体性能。建议测试文件至少是磁盘容量的两倍,或者直接用裸盘测试。

6.4 多job共享文件的锁竞争

用--numjobs多job测试时,如果多个job操作同一个文件,默认会有文件锁竞争,导致结果异常。解决办法是每个job用独立的文件,通过--filename_format参数指定文件名格式,比如--filename_format='testfile.$jobnum'。或者用--stonewall让job串行执行,但这样就不是真正的并发了。

6.5 系统参数对测试结果的影响

Linux的IO调度器、预读参数、脏页回写策略都会影响fio结果。测试前建议确认IO调度器设置:NVMe盘用none,SSD用mq-deadline或none,机械盘用bfq或mq-deadline。可以用cat /sys/block/sdX/queue/scheduler查看,用echo修改。另外vm.dirty_ratio和vm.dirty_background_ratio在写入测试时影响很大,测试前最好确认这些参数符合预期。

7. 把fio用进日常运维的几个思路

fio不只是一个临时排查工具,完全可以纳入日常运维体系。我目前的做法是:新盘上线前跑一套标准测试,记录基线数据;业务变更后跑对比测试,确认性能没有退化;定期跑稳定性测试,观察性能衰减趋势。

具体实施上,可以把常用测试场景写成脚本,参数用变量控制,结果输出成JSON格式存档。这样每次测试的配置和结果都可追溯,方便对比。下面是一个简化的脚本框架:

#!/bin/bash TEST_DIR="/data/fio_test" RESULT_DIR="/var/log/fio_results" TIMESTAMP=$(date +%Y%m%d_%H%M%S) mkdir -p $RESULT_DIR run_test() { local name=$1 local rw=$2 local bs=$3 local iodepth=$4 local numjobs=$5 fio --name=$name \ --filename=$TEST_DIR/testfile \ --size=4G \ --rw=$rw \ --bs=$bs \ --direct=1 \ --ioengine=libaio \ --iodepth=$iodepth \ --numjobs=$numjobs \ --runtime=60 \ --time_based \ --ramp_time=10 \ --group_reporting \ --output-format=json \ --output=$RESULT_DIR/${name}_${TIMESTAMP}.json } run_test "randread_4k" "randread" "4k" 32 4 run_test "randwrite_4k" "randwrite" "4k" 32 4 run_test "seqread_1m" "read" "1m" 16 1 run_test "seqwrite_1m" "write" "1m" 16 1

这个脚本跑完会生成四个JSON文件,分别对应随机读、随机写、顺序读、顺序写。后续可以用jq或Python解析这些JSON,提取关键指标做趋势分析。

另外提醒一点:测试目录最好单独挂载,避免测试产生的IO影响系统盘和其他业务。测试时间尽量选在业务低峰期,减少对生产的影响。如果必须在业务高峰期测试,务必控制测试强度和时长,并做好监控。

8. 几个容易被忽略的细节

--ioengine的选择值得单独说一下。Linux下常用的是libaio和io_uring。libaio是传统异步IO引擎,兼容性好但队列深度受限于内核参数。io_uring是较新的异步IO框架,性能更好但需要内核5.1以上。如果内核支持,优先用io_uring。可以用--ioengine=io_uring指定。

--numa_cpu_nodes和--numa_mem_policy在多路服务器上影响很大。如果测试进程和磁盘不在同一个NUMA节点,跨节点访问会引入额外延迟。可以用numactl --hardware查看拓扑,用fio的NUMA参数绑定到正确的节点。

--write_iops_log、--write_bw_log、--write_lat_log可以输出详细的时序日志,配合fio_generate_plots脚本能画出性能随时间变化的曲线。做深度分析时这些日志很有价值,能看到性能抖动和趋势变化。

最后说一个心态问题:fio的结果只是参考,不是绝对真理。真实业务的IO模式比fio模拟的复杂得多,fio测出来的数字好不代表业务一定流畅,数字差也不代表业务一定卡。把fio当作评估工具而不是判决工具,结合业务监控和实际体验综合判断,才是正确的用法。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询