fio工具简介及使用说明

一、简介

fio是一个I/O标准测试和硬件压力验证工具,它支持多种不同类型的I/O引擎,支持对块设备和文件系统测试,广泛用于标准测试、QA、验证测试等,支持Linux, FreeBSD, NetBSD,OS X, OpenSolaris, AIX, HP-UX, Windows等操作系统。

对于性能测试,fio能够测试存储系统(磁盘、阵列、文件系统)的最大IO能力、网络带宽,不同的IO负载能力测试,支持几乎所有的存储描述参数,可定制多种测试模式。

fio的特性:

  • 支持应用的并发线程数目、IO队列深度设置
  • 支持自定义IO引擎,实现在不同平台、不同应用测试的IO定制
  • 支持顺序或随机读、写数据比例调整
  • 支持测试末制定,可设置读写块大小、读写时间
  • 支持读、写数据的一致性校验
  • 支持自定义IO调度器(cfq、noop等IO调度算法)
  • 可测试分布式集群文件系统(ceph、hdfs)
  • 大量对CPU,内存,进程/线程,文件,IO特性的配置

二、在CentOS上安装fio测试工具

解压fio-2.1.10.tar

tar –xvf fio-2.1.10.tar

需要安装libaio作为io engine,只有libaio还不够,还需要安装libaio-devel

yum install libaio*

编译安装(需要先安装libaio,然后才能够编译fio,否则编译出的fio不会识别libaio引擎)

./configure && make && make install

三、使用fio进行测试

fio最初是用来节省为特定负载专门写测试程序,或者进行性能测试,或者找到和重现bug。

典型的fio工作过程

1)写一个job文件来描述要仿真的io负载,一个job文件可以控制产生任意数目的线程和文件。典型的job文件有一个global端(定义共享参数),一个或者多个job段(描述具体要产生的job)

2)运行时,fio从文件读取这些参数,作出处理,并根据这些参数描述,启动仿真线程/进程

运行方式:

fio job_file

fio会根据job_file文件中的内容来运行,可以在命令行中指定多个job file。fio会串行运行这些文件。

如果某个job file只包含一个job,可以在命令行中直接给出参数运行,不需要job file。命令行参数和job file参数的格式是一样的,在job file中的参数iodepth=2,在命令行中可以写成-iodepth 2或者-iodepth=2

fio不需要使用root来执行,除非使用到的文件或者设备需要root权限,一些选项可能会被限制。如内存锁、io调度器、nice value降级等。

job_file格式采用经典的ini文件,[]中的内容表示job name,可以采用任意的ascii字符,global除外,global有特殊的意义,global section描述了job file中各个job的默认配置项,一个job section可以覆盖global section中的参数,一个job file中可以包含几个global section,一个job只会受它上面的global section的影响。“;”和“#”用于注释。

两个进程,分别从一个128M文件中,随机读的job file

;–start job file– 
[global] 
rw=randread 
size=128m   

[job1]
   
[job2] 

;–end job file–

job1和job2的section都是空的,因为所有的描述参数都是共享的,没有给出filename选项,fio会为每一个job创建一个文件名,如果用命令写,是:

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–

没有global section,只有一个job section。

此实例解释为:采用libaio引擎,io深度为4,随机写,块大小为32k,非direct io,四个进程每个进程随机写64M文件,也可以采用以下命令

fio -name=random-writers -ioengine=libaio -iodepth-4 -rw=randwrite -bs=32k -direct=0 -size=64m -numjobs=4 

保留keywords

fio有一些保留keywords,在内部将其替换成合适的值,这些keywords是:

$pagesize   当前系统的页大小

$mb_memory 系统的总内存的大小,以MB为单位

$ncpus 在线有效的cpu数

这引起在命令行中和job file中都可以用,当job运行的时候,会自动的用当前系统的徝进行替换。支持简单的数学计算,如:

size=8*$mb_memory

四、fio选项说明

常用选项:

--direct=1:direct=1表示绕过机器自带的缓存,0表示使用缓存

--ioengine:表示能够使用的io引擎,可以通过fio --enghelp查看能够使用的io引擎

sync:基本的read,write。lseek定位

psync:基本的pread、pwrite

vsync:基本的readv,writev

libaio:linux专用异步io

posxaio:glibc posix异步io

solarisaio:solaris特有的异步io

mmap:文件通过内存映射到用户空间,使用memcpy写入和读取数据

splice:使用splice和vmsplice在用户空间和内核空间传输数据

syslet-rw 使用syslet 系统调用来构造普通的read/write异步IO

sg SCSI generic sg v3 io.可以是使用SG_IO ioctl来同步,或是目标是一个sg字符设备,我们使用read和write执行异步IO

null 不传输任何数据,只是伪装成这样。主要用于训练使用fio,或是基本debug/test的目的。

net 根据给定的host:port通过网络传输数据。根据具体的协议,hostname,port,listen,filename这些选项将被用来说明建立哪种连接,协议选项将决定哪种协议被使用。

netsplice 像net,但是使用splic/vmsplice来映射数据和发送/接收数据。

cpuio:不传输任何数据,但是要根据cpuload和cpucycle选项占用cpu周期,cpuload=85将使用job不做任何io,但是占用85%的cpu周期,在smp机器上,需要使用numjobs=来获取cpu,因为cpuload只会载入单个cpu

guasi GUASI IO引擎是一般的用于异步IO的用户空间异步系统调用接口

rdma RDMA I/O引擎支持RDMA内存语义(RDMA_WRITE/RDMA_READ)和通道主义(Send/Recv)用于InfiniBand,RoCE和iWARP协议

external 指明要调用一个外部的IO引擎(二进制文件)。e.g. ioengine=external:/tmp/foo.o将载入/tmp下的foo.o这个IO引擎

--thread:表示使用pthread_create代替fork,pthread_create是用来创建线程的,而fork是用来创建进程的。区别能够通过top和top -H看出来,如果不加--thread的话,numjobs设置多个的时候使用top能够看到存在多个fio进程,使用--thread之后,numjobs设置多个的时候使用top只能够看到一个fio进程,但是与此同时使用top -H能够看到存在多个fio线程

--filename:需要测试的文件名称,可以是一个指定的文件也可以是待测试的磁盘,如果不指定filename则fio会设定一个默认的名字,如果ioengine是net的话,文件名以host,port,protocol命令,如果ioengine是基于文件的话,可以通过:来分割一系列文件,如filename=/dev/sda:/dev/sdb打开两个文件

例如fio --name=global --rw=randread --size=128m --name=job1 --name=job2

会生成job1.0.0和job2.0.0两个文件

--name:用于输出信息的名字,如果不设置,fio输出信息将会采用job name,如果设置将会使用设置的名字

--rw:设置读写测试模式,可选randwrite表示测试随机写IO,randread表示测试随机读IO,randrw表示测试随机读写IO,read表示顺序读,write表示顺序写,rw/readwrite表示顺序混合读写

对于混合io类型,默认是50%的读,50%的写.

如果在rw的参数后面添加上一个整数,则有两种情况:

1)对于随机io读写而言,表示在下一次随机io之前进行读写的次数,具体情况需要配合rw_sequencer参数使用,例如

-rw=randread:8 -rw_sequencer=sequential

表示每8次io才会产生一个新的随机io,默认是每次io之后都会产生一个随机io,现在是执行8次的连续io之后才会产生一次随机io

-rw=randread:8 -rw_sequencer=identical

表示会产生8次相同的offset,然后才会生成一个新的offset,就是8次相同的偏移之后才产生下一次随机

2)对于顺序io而言,表示offset的大小

-rw=write:4k

表示每次写之后会跳过4k,将顺序的io转换为带洞的io

--rw_sequencer:控制rw后面offset的含义,可以接收的值是:sequential表示产生顺序offset,identical表示产生相同offset

--bs:单次IO的块文件大小,默认为4k。如果是一个值的话,表示对读写都生效,如果使用一个逗号写两个值的话,则前面一个表示读的大小,后面一个表示写的大小

bs=4k,8k表示读采用4k,写采用8k

--bsrange=512-2048:单次IO块文件大小范围

--size:测试io的数据大小,fio将会执行到size大小的数据都传输完成,除非设定了运行时间runtime,除非有设定nrfiles和filesize选项,fio将会在job定义的文件中平分这个大小,如果这个值不设置,fio将会使用这个文件或者设备的总大小,如果文件不存在,size选项一定要给出,也可以给出一个1到100的百分比,表示fio将会使用给定文件或设备的百分比空间。

--iodepth:如果io引擎是异步的,我们需要设定io的队列深度,默认是1,可以设置一个更大的值来提供高并发,iodepth大于1不会影响同步io

--direct=bool:true表示采用no buffered io。ZFS和Solaris不支持direct io,在windows同步IO引擎不支持direct io

--buffered=bool:true表示采用buffered io,默认是true,是direct的反义词

--nrfile=int:用于job的文件数目,默认是1

--openfiles=int:在同一时间内可以同时打开的文件数目,默认是nrfiles一致的,可以设置小一些来限制同时打开的文件数目

--numjobs=int:创建job数目,可以创建大量的进程/线程执行

--description=str:job的说明信息,只在输出文件描述信息的时候才有作用

--directory=str:使用文件的路径前缀,默认是.

--opendir=str:fio递归添加目录下和子目录下的所有文件

--lockfile=str:fio在文件上执行io之前默认是不加文件锁的,这样的话,当多个线程在这个文件上执行io,会造成结果的不一致,这个选项可以用来共享文件的负载,支持的锁类型:

none 默认不使用锁

exclusive:排它锁

readwrite:读写锁

在后面可以添加一个数字后缀,表示每个线程将会执行这个数字指定的io之后才会放弃锁,因为锁的开销是很大的,这种方式可以加速io

--kb_base=int:size转换单位,1000或1024,默认是1024

--fallocate=str:如何准备测试文件,

none 不执行预分配空间

posix 通过posix_fallocate()预分配空间

keep 通过fallocate()预分配空间

0 none的别名,出于兼容性

1 posix的别名,出于兼容性

并不是在所有的平台上都有效,‘keep’仅在linux上有效,ZFS不支持。默认为‘posix’

--filesize:单个文件的大小,可以是一个范围,在这种情况下,fio将会在一个范围内选择一个大小来决定单个文件大小,如果没有设置,所有文件将会是相同的大小

--file_device=bool,fill_fs=bool:填满空间直到终止条件ENOSPC,只对顺序写有意义,对于读,首先要填满挂载点然后才启动io,对于裸设备没有意义,因为它的大小系统已经知道了。如果写超出文件不会返回ENOSPC。

--blockalign=int,ba=int:配置随机io的对齐边界,默认是和blocksize一致的,对于随机map来说没有作用。

--bssplit=str:可以更加精确的控制block size,可以用来定义各个块大小所占的权重,格式是

bssplit=blocksize/percentage;blocksize/percentage

bssplit=4k/10:64k/50:32k/40

表示产生50% 54k的块,10% 4k的块,40% 32k的块。

可以分别为读写设置

bssplit=2k/50:4k/50,4k/90:8k/10

产生这样的负载:读(50% 64k的块,50% 4k的块),写(90% 4k的块, 10% 8k的块)

--blocksize_unaligned,bs_unaligned:如果这个选项被设置的,在bsrange范围内的大小都可以产生,这个选项对于direct io没有作用,因为对于direct io至少需要扇区对齐

--zero_buffers:如果这个选项设置的话,IO buffer全部位将被初始为0,如果没有置位的话,将会是随机数.

--refill_buffers:如果这个选项设置的话,fio将在每次submit之后都会将重新填满IO buffer,默认都会在初始是填满,以后重复利用。这个选项只有在zero_buffers没有设置的话,这个选项才有作用。

--rwmixread=int:混合读写中,读占的百分比

--rwmixwrite=int:混合读写中,写占的百分比;如果rwmixread=int和rwmixwrite=int同时使用的话并且相加不等于100%的话,第二个值将会覆盖第一个值。这可能要干扰比例的设定,如果要求fio来限制读和写到一定的比率。在果在这种情况下,那么分布会的有点的不同。

--nice=int:根据给定的nice值来运行这个job

--prio=int:设置job的优先级,linux将这个值限制在0-7之间,0是最高的。

--thinktime=int:上一个IO完成之后,拖延x毫秒,然后跳到下一个。可以用来访真应用进行的处理。

--thinktime_blocks:只有在thinktime设置时才有效,控制在等等‘thinktime’的时间内产生多少个block,如果没有设置的话,这个值将是1,每次block后,都会将等待‘thinktime’us。

--rate=int:限制job的带宽。

e.g.rate=500k,限制读和写到500k/s

e.g.rate=1m,500k,限制读到1MB/s,限制写到500KB/s

e.g.rate=,500k , 限制写到500kb/s

e.g.rate=500k, 限制读到500KB/s

--ratemin=int:告诉fio尽最在能力来保证这个最小的带宽,如果不能满足这个需要,将会导致程序退出。

--rate_iops=int:将带宽限制到固定数目的IOPS,基本上同rate一样,只是独立于带宽.

--rate_iops_min=int:如果fio达不到这个IOPS的话,将会导致job退出。

--cpumask=int:设置job使用的CPU.给出的参数是一个掩码来设置job可以运行的CPU。所以,如果要允许CPU在1和5上的话,可以通过10进制数来设置(1

--cpus_allowed=str:功能同cpumask一样,但是允许通过一段文本来设置允许的CPU。e.g.上面的例子可是这样写cpus_allowed=1,5。这个选项允许设置一个CPU范围,如cpus_allowed=1,5,8-15

--startdelay=time:o启动几秒后再启动job。只有在job文件包含几个jobs时才有效,是为了将某个job延时几秒后执行。

--time_based:如果设置的话,即使file已被完全读写或写完,也要执行完runtime规定的时间。它是通过循环执行相同的负载来实现的。

--ramp_time=time:设定在记录任何性能信息之前要运行特定负载的时间。这个用来等性能稳定后,再记录日志结果,因此可以减少生成稳定的结果需要的运行时间。

--exitall:当一个job退出时,会终止运行其它的job,默认是等待所有的job都完成,FIO才退出,但有时候这并不是我们想要的。

--unlink=bool: 完成后将删除job产生的文件。默认是not,如果设置为true的话,将会花很多时间重复创建这些文件。

--loops=int:重复运行某个job多次,默认是1

--write_bw_log=str:在job file写这个job的带宽日志。可以在他们的生命周期内存储job的带宽数据。内部的fio_generate_plots脚本可以使用gnuplot将这些文本转化成图。

--write_lat_log=str:同write_bw_log类似,只是这个选项可以存储io提交,完成和总的响应时间。如果没有指定文件名,默认的文件名是jobname_type.log。即使给出了文件名,fio也会添加两种类型的log。

e.g.如果我们指定write_lat_log=foo

实际的log名将是foo_slat.log,foo_slat.log和foo_lat.log.这会帮助fio_generate_plot来自动处理log

--write_iops_log=str:类似于write_bw_log,但是写的是IOPS.如果没有给定文件名的话,默认的文件名是jobname_type.log。

--log_avg_msec=int:默认,fio每完成一个IO将会记录一个日志(iops,latency,bw log)。当向磁盘写日志的时候,将会很快变的很大。设置这个选项的话,fio将会在一定的时期内平均这些值,指少日志的数量,默认是0

--disk_util=bool:产生磁盘利用率统计信息。默认是打开的

--disable_lat=bool:是否统计延迟

--disable_clat=bool

--disable_slat_bool

--disable_bw=bool

--clat_percentiles=bool:允许报告完成完成响应时间的百分比

--uid=int:不是使用调用者的用户来执行,而是指定用户ID

--runtime=1000:测试时间为1000秒,如果不写则一直将size大小文件分bs大小的块写完为止.控制fio在执行设定的时间后退出执行。很难来控制单个job的运行时间,所以这个参数是用来控制总的运行时间。

--rwmixwrite=30:在混合读写的模式下,写占30%

--group_reporting:显示结果汇总每个进程的信息

--lockmem=1g:只使用1g内存进行测试

随机性选项:

--randrepeat:在随机读写的时候指定,如果指定了这个参数表示在随机读、随机写产生的位置是可重复的,默认设置是true

randrepeat & randseed=XX : 如果randseed设置了自定义的值,randrepeat将强制变成False,如果randseed没有设置值(默认137)randrepeat=1,那么这个设置不言而喻,相当于每次都用同样的randseed,当然就是randrepeatable的测试。

randrepeat=0 & randseed=None: 如果测试的时候randrepeat设置为false,同时也没有指定seed,这个时候randseed就是去读/dev/urandom文件获取一个随机的seed

--norandommap:一般情况下,fio做随机IO将会覆盖文件的每一个block,如果设置这个选项,fio在选择新的block的时候不会查询历史,也就意味着可能有一些块没有读或者写,有一些块会读写很多次

--softrandommap:默认是disable,如果设置为1,表示:因为randommap是需要使用内存来做历史记录的,但是在某些情况下可能会出现allocate bit map内存失败的情况,那么测试会自动变为norandommap,并且不会报错,softrandommap如果设置为disable,fio在分配内存失败之后会报错退出。

--random_distribution:随机分布参数,fio可以模拟不同类型的随机分布,可以使某些区域的随机概率高,某些区域的随机概率低,模拟随机数据的冷热性。

可以取值:

random:均匀分布

zipf:zipf分布

pareto:帕累托分布

zoned:直接某个区域内指定io多少

narmal:高斯分布

后面这几个分布各有不同,其实达到的目的都很类似,如果使用了非均匀分布的参数,会强制指定norandommap=1,这些非均匀分布和randommap要实现的目的是冲突的。

--group_reporting:如果‘numjobs’设置的话,我们感兴趣的可能是打印group的统计值,而不是一个单独的job。这在‘numjobs’的值很大时,一般是设置为true的,可以减少输出的信息量。如果‘group_reporting’设置的话,fio将会显示最终的per-groupreport而不是每一个job都会显示

--use_os_rand=bool:fio可以使用操作系统的随机数生成器,也可以使用fio内部的随机数生成器,默认采用fio内部的生成器,质量更好,速度更快

fio测试结果中各项含义:

bw:带宽 kb/s

iops:每秒IO数目

runt:总运行时间

lat(msec):延迟(毫秒)

当fio完成的时候(或是通过ctrl-c终止的时候),将会打印每一个线程的数据,每个group的数据,和磁盘数据。

io= 执行了多少M的IO

bw= 平均IO带宽

iops=   IOPS

runt= 线程运行时间

slat 提交延迟

clat 完成延迟

lat响应时间

bw 带宽

cpu利用率

IO depths=io队列

IO submit=单个IO提交要提交的IO数

IO complete= Like the above submit number, but for completions instead.

IO issued= The number of read/write requests issued, and how many

of them were short.

IO latencies=IO完延迟的分布

io= 总共执行了多少size的IO

aggrb= group总带宽

minb= 最小.平均带宽.

maxb= 最大平均带宽.

mint= group中线程的最短运行时间.

maxt= group中线程的最长运行时间.

ios= 所有group总共执行的IO数.

merge= 总共发生的IO合并数.

ticks= Number of ticks we kept the disk busy.

io_queue= 花费在队列上的总共时间.

util= 磁盘利用率

fio混合随机读写测试

fio -filename=/dev/sdb -direct=1 -iodepth 1 -thread -rw=randrw -rwmixread=70 -ioengine=psync -bs=16k -size=200G -numjobs=30 -runtime=100 -group_reporting -name=mytest1

测试解读:

测试磁盘/dev/sdb,忽略系统buffer,io深度为1,使用pthread_create替代fork,测试模式为随机读写,测试中读比例占70%,io引擎使用psync,测试单块大小为16k,测试总大小为200G,线程数为30,运行时间为100s,采用合并report,测试范例名称为mytest1

mytest1: (g=0): rw=randrw, bs=16K-16K/16K-16K/16K-16K, ioengine=psync, iodepth=1

...

fio-2.1.10

Starting 30 threads

Jobs: 30 (f=30): [mmmmmmmmmmmmmmmmmmmmmmmmmmmmmm] [100.0% done] [291.1MB/126.7MB/0KB /s] [18.7K/8106/0 iops] [eta 00m:00s]

mytest1: (groupid=0, jobs=30): err= 0: pid=76884: Wed Mar 13 11:26:47 2019

read : io=29423MB, bw=301284KB/s, iops=18830, runt=100003msec

clat (usec): min=32, max=7585, avg=1540.58, stdev=781.56

lat (usec): min=33, max=7585, avg=1540.66, stdev=781.56

clat percentiles (usec):

| 1.00th=[ 772], 5.00th=[ 876], 10.00th=[ 916], 20.00th=[ 980],

| 30.00th=[ 1004], 40.00th=[ 1048], 50.00th=[ 1144], 60.00th=[ 1384],

| 70.00th=[ 1640], 80.00th=[ 2256], 90.00th=[ 2960], 95.00th=[ 3088],

| 99.00th=[ 3504], 99.50th=[ 3728], 99.90th=[ 4192], 99.95th=[ 4448],

| 99.99th=[ 5728]

bw (KB /s): min= 7040, max=17824, per=3.34%, avg=10051.32, stdev=853.11

write: io=12631MB, bw=129340KB/s, iops=8083, runt=100003msec

clat (usec): min=33, max=2385, avg=119.53, stdev=94.54

lat (usec): min=33, max=2385, avg=119.75, stdev=94.54

clat percentiles (usec):

| 1.00th=[ 57], 5.00th=[ 64], 10.00th=[ 71], 20.00th=[ 77],

| 30.00th=[ 82], 40.00th=[ 87], 50.00th=[ 91], 60.00th=[ 97],

| 70.00th=[ 106], 80.00th=[ 125], 90.00th=[ 207], 95.00th=[ 274],

| 99.00th=[ 628], 99.50th=[ 700], 99.90th=[ 908], 99.95th=[ 1032],

| 99.99th=[ 1352]

bw (KB /s): min= 2804, max= 7456, per=3.34%, avg=4315.92, stdev=454.09

lat (usec) : 50=0.13%, 100=19.22%, 250=9.00%, 500=1.58%, 750=0.61%

lat (usec) : 1000=18.06%

lat (msec) : 2=36.37%, 4=14.91%, 10=0.13%

cpu : usr=0.20%, sys=0.89%, ctx=2691503, majf=0, minf=447

IO 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 : total=r=1883084/w=808399/d=0, short=r=0/w=0/d=0

latency : target=0, window=0, percentile=100.00%, depth=1

Run status group 0 (all jobs):

READ: io=29423MB, aggrb=301284KB/s, minb=301284KB/s, maxb=301284KB/s, mint=100003msec, maxt=100003msec

WRITE: io=12631MB, aggrb=129339KB/s, minb=129339KB/s, maxb=129339KB/s, mint=100003msec, maxt=100003msec

Disk stats (read/write):

sdb: ios=1881566/807801, merge=0/0, ticks=2884240/91080, in_queue=2976440, util=100.00%

结果主要看上面红色部分,表示带宽和iops.

  • 28
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

aolitianya

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值