1.硬盘I/O测试类型
在日常测试中,硬盘I/O测试类型主要有以下几种类型
- 随机读、随机写、随机读写
- 顺序读、顺序写、顺序读写
2.FIO介绍
FIL是Linux中开源的一款IOPS测试工具,主要用来对硬盘进行压力测试和性能验证。使用FIO可以产生多线程或进程来执行特定类型的I/O操作,通过编写配置文件或直接命令行去执行测试动作,相当于是一个多线程的IO生成工具。使用FIO工具可生成多种IO模式来测试硬盘设备性能。其开源地址为:https://github.com/axboe/fio
使用FIO工具,可根据测试需求设置读写比例等,例如80%读,20%写等等
2.1 FIO安装
以Ubuntu 22.04为例,安装命令如下所示:
sudo apt-get update && sudo apt-get install -y fio
2.2 常用参数
参数名 | 功能 | 取值示例 |
---|---|---|
bs | 定义I/O的块大小(block size),单位是k、K、m和M等,默认I/O块大小为4KB | 4KB |
ioengine | 定义fio如何下发I/O请求,通常有同步I/O和异步I/O - 同步I/O一次只能发出一个I/O请求,等待内核完成后才返回。这样对于单个线程I/O队列深度总是小于1,但是可以透过多个线程并发执行来解决。通常会用16~32个线程同时工作把I/O队列深度塞满 - 异步I/O则通常使用libaio这样的方式一次提交一批I/O请求,然后等待一批的完成,减少交互的次数,会更有效率 |
libaio |
iodepth | 定义测试时的I/O队列深度,默认为1 | 1 |
direct | direct模式 - 1:表示使用direct I/O,忽略 I/O 缓存,数据直写 - 0:表示使用buffered I/O - 默认为True |
1 |
rw | 读写模式,可取的值 - 顺序读:read - 顺序写:write - 随机读:randread - 随机写:randwrite - 混合随机读写:randrw - 混合顺序读写:readwrite |
read |
time_based | 指定采用时间模式。无需设置该参数值,只要 FIO 基于时间来运行 | |
runtime | 指定测试时长,即 FIO 运行时长,以秒为单位 | 600 |
refill_buffers | FIO 将在每次提交时重新填充 I/O 缓冲区,默认设置是仅在初始时填充并重用该数据 | |
norandommap | 在进行随机 I/O 时,FIO 将覆盖文件的每个块,若给出此参数,则将选择新的偏移量而不查看 I/O 历史记录 | |
randrepeat | 随机序列是否可重复 - True或1:表示随机序列可重复 - False或0:表示随机序列不可重复 - 默认为 True |
1 |
group_reporting | 定义测试结果显示模式,group_reporting 表示汇总每个进程的统计信息,而非以不同job汇总展示信息 | |
name | 定义测试任务名称 | |
filename | 定义测试文件/设备的名称 | /dev/vdb |
size | 定义测试I/O操作的数据量,如果未指定runtime这类参数,fio会将指定大小的数据量全部读/写完成,然后才停止测试。 - 该参数的值,可以是带单位的数字,比如size=10G,表示读/写的数据量为10GB;也可是百分数,比如size=20%,表示读/写的数据量占该设备总文件的20%的空间 |
500GB |
rwmixwrite | 在混合读写的模式下,写占比 | 30 |
numjobs | 定义测试的并发线程数 |
2.3 FIO使用
2.3.1 以命令行方式运行
- 测试随机写IOPS
sudo fio -direct=1 -iodepth=32 -rw=randwrite -ioengine=libaio -bs=4k -size=20G -numjobs=16 -runtime=600 -group_reporting -filename=/${MOUNT_PATH}}$/${TEST_FILE_NAME} -name={RAND_WRITE_TEST}
- 测试随机读IOPS
sudo -direct=1 -iodepth=32 -rw=randread -ioengine=libaio -bs=4k -size=20G -numjobs=16 -runtime=600 -group_reporting -filename=/dev/{DEVICE_NAME} -name={RAND_READ_TEST}
- 测试写吞吐量
sudo fio -direct=1 -iodepth=64 -rw=write -ioengine=libaio -bs=4k -size=20G -numjobs=16 -runtime=600 -group_reporting -filename=/${MOUNT_PATH}}$/${TEST_FILE_NAME} -name={WRITE_TEST}
- 测试读吞吐量
sudo fio -direct=1 -iodepth=64 -rw=read -ioengine=libaio -bs=4k -size=20G -numjobs=16 -runtime=600 -group_reporting -filename=/dev/{DEVICE_NAME} -name={READ_TEST}
2.3.2 以配置文件方式运行
2.3.2.1 常规配置
fio除支持基于命令行运行之外,还支持基于配置文件的形式运行,其格式为经典的ini格式,格式如下所示:
- 使用 [ ] 来定义Job名称,但不能使用
global
- 注释使用 ; 或 #
; -- start job file --
[global]
rw=randread
size=128m[job1][job2]; -- end job file --
以上配置文件运行效果等同于以下命令
# fio --name=global --rw=randread --size=128m --name=job1 --name=job2
再来看看以下示例
; -- start job file --
[random-writers]
ioengine=libaio
iodepth=4
rw=randwrite
bs=32k
direct=0
size=64m
numjobs=4
; -- end job file --
以上配置文件运行效果等同于以下命令
# fio --name=random-writers --ioengine=libaio --iodepth=4 --rw=randwrite --bs=32k --direct=0 --size=64m --numjobs=4
除此之外,fio还支持通过共享测试文件来达到快速测试,配置文件写法如下所示:
; -- start job file including.fio --
[global]
filename=/tmp/test
filesize=1m
;全局包含的测试文件
include glob-include.fio[test]
rw=randread
bs=4k
time_based=1
runtime=10
include test-include.fio
; -- end job file including.fio --
2.3.2.2 使用环境变量
在配置文件中,fio同样支持使用环境变量,在配置文件中的引用格式为${VAR_NAME}
,示例如下所示:
; -- start job file --
[random-writers]
rw=randwrite
size=${SIZE}
numjobs=${NUMJOBS}
; -- end job file --
执行以下命令
SIZE=64m NUMJOBS=4 fio jobfile.fio
在使用环境变量之后,等效的配置文件为:
; -- start job file --
[random-writers]
rw=randwrite
size=64m
numjobs=4
; -- end job file --
2.3.3 实践
- 1.编写配置文件
[global]
ioengine=libaio
direct=1
iodepth=1
bs=4k
numjobs=32
runtime=120
size=5G
randrepeat=0
group_reporting[rand-read-test]
rw=randread
filename=/dev/sde[rand-write-test]
rw=randwrite
filename=/home/data4/fio.randwrite.test[rand-read-write-test]
rw=randrw
filename=/home/data4/fio.rand-read-write.test
- 2.运行
sudo fio fio.conf
- 3.结果分析
运行输出结果如下所示:
# sudo fio fio.conf
rand-read-test: (g=0): rw=randread, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=libaio, iodepth=1
...
rand-write-test: (g=0): rw=randwrite, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=libaio, iodepth=1
...
rand-read-write-test: (g=0): rw=randrw, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=libaio, iodepth=1
...
fio-3.28
Starting 96 processes
Jobs: 96 (f=96): [r(32),w(32),m(32)][100.0%][r=151MiB/s,w=104MiB/s][r=38.6k,w=26.7k IOPS][eta 00m:00s]
rand-read-test: (groupid=0, jobs=96): err= 0: pid=3058638: Wed Aug 20 10:47:05 2025read: IOPS=41.0k, BW=160MiB/s (168MB/s)(18.8GiB/120002msec)slat (usec): min=2, max=84346, avg=237.56, stdev=917.90clat (nsec): min=882, max=105729k, avg=934390.79, stdev=2021217.42lat (usec): min=3, max=110005, avg=1172.49, stdev=2263.52clat percentiles (usec):| 1.00th=[ 3], 5.00th=[ 184], 10.00th=[ 285], 20.00th=[ 404],| 30.00th=[ 490], 40.00th=[ 578], 50.00th=[ 685], 60.00th=[ 832],| 70.00th=[ 1020], 80.00th=[ 1254], 90.00th=[ 1598], 95.00th=[ 1893],| 99.00th=[ 2966], 99.50th=[ 5997], 99.90th=[28705], 99.95th=[50594],| 99.99th=[77071]bw ( KiB/s): min=93770, max=203572, per=100.00%, avg=164165.63, stdev=311.35, samples=15296iops : min=23442, max=50892, avg=41034.97, stdev=77.90, samples=15296write: IOPS=25.6k, BW=99.9MiB/s (105MB/s)(11.7GiB/120002msec); 0 zone resetsslat (usec): min=6, max=99557, avg=865.97, stdev=1946.04clat (nsec): min=1438, max=97151k, avg=997772.53, stdev=1607120.25lat (usec): min=56, max=105108, avg=1864.40, stdev=2650.19clat percentiles (usec):| 1.00th=[ 161], 5.00th=[ 285], 10.00th=[ 371], 20.00th=[ 498],| 30.00th=[ 603], 40.00th=[ 701], 50.00th=[ 807], 60.00th=[ 922],| 70.00th=[ 1057], 80.00th=[ 1237], 90.00th=[ 1598], 95.00th=[ 2040],| 99.00th=[ 3490], 99.50th=[ 5407], 99.90th=[20841], 99.95th=[33162],| 99.99th=[64750]bw ( KiB/s): min=52498, max=131745, per=100.00%, avg=102401.73, stdev=240.76, samples=15296iops : min=13117, max=32932, avg=25595.54, stdev=60.25, samples=15296lat (nsec) : 1000=0.01%lat (usec) : 2=0.55%, 4=0.68%, 10=0.15%, 20=0.01%, 50=0.01%lat (usec) : 100=0.27%, 250=4.76%, 500=20.56%, 750=23.99%, 1000=16.98%lat (msec) : 2=27.58%, 4=3.76%, 10=0.37%, 20=0.13%, 50=0.13%lat (msec) : 100=0.04%, 250=0.01%cpu : usr=0.89%, sys=3.70%, ctx=13650352, majf=0, minf=6861IO depths : 1=100.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%submit : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%complete : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%issued rwts: total=4917306,3068451,0,0 short=0,0,0,0 dropped=0,0,0,0latency : target=0, window=0, percentile=100.00%, depth=1Run status group 0 (all jobs):READ: bw=160MiB/s (168MB/s), 160MiB/s-160MiB/s (168MB/s-168MB/s), io=18.8GiB (20.1GB), run=120002-120002msecWRITE: bw=99.9MiB/s (105MB/s), 99.9MiB/s-99.9MiB/s (105MB/s-105MB/s), io=11.7GiB (12.6GB), run=120002-120002msecDisk stats (read/write):sde: ios=4798086/3074895, merge=44/137845, ticks=4552421/2533315, in_queue=7085984, util=99.97%
每个执行任务的数据方向的I/O统计数据
- IOPS 相关指标可以查看IOPS=***内容
- 吞吐量相关指标可以查看BW=***内容
- 时延相关指标可以查看lat相关内容
- 提交延迟相关指标可以查看slat相关内容
- 完成延迟相关指标可以查看clat相关内容
- CPU使用率相关指标可以查看CPU相关内容
- IO depths表示I/O在作业生命周期中的分布
Run status group x 代表值含义
- bw: 总带宽以及最小和最大带宽
- io: 该组中所有线程执行的累计I/O
- run: 这组线程中最小和最长的运行时。
Disk stats 代表值含义
- ios:所有组的I/O个数
- merge:I/O调度器执行的总合并数
- ticks:使磁盘繁忙的滴答数
- in_queue:在磁盘队列中花费的总时间
- util:磁盘利用率。
2.4 其他
- 1.查看支持的ioengine
# fio --eng help
输出结果如下所示:
Available IO engines:libpmemdev-daxpmemblkrbdradosrdmalibaioio_uringsgmtdgfapi_asyncgfapisplicee4defragfallocposixaioexecfiledeletefilestatfilecreateftruncatenetnetsplicenullsyncpsyncvsyncpvsyncpvsync2mmapcpuio
官方帮助文档:https://fio.readthedocs.io/en/latest/fio_doc.html#command-line-options
- 2.查看各选项说明
# fio --cmdhelp
输出结果如下所示:
description : Text job description
name : Name of this job
wait_for : Name of the job this one wants to wait for before starting
filename : File(s) to use for the workloadlockfile : Lock file when doing IO to it
directory : Directory to store files in
filename_format : Override default $jobname.$jobnum.$filenum naming
unique_filename : For network clients, prefix file with source IP
opendir : Recursively add files from this directory and down