FIO是测试IOPS的非常好的工具,用来对硬件进行压力测试和验证,支持13种不同的I/O引擎,包括:sync,mmap, libaio, posixaio, SG v3, splice, null, network, syslet, guasi, solarisaio 等等。
fio 官网地址:http://freshmeat.net/projects/fio/
一,FIO安装
wget http://brick.kernel.dk/snaps/fio-2.2.5.tar.gz
yum install libaio-devel
tar -zxvf fio-2.2.5.tar.gz
cd fio-2.2.5
make
make install
二,FIO用法:
随机读:(可直接用,向磁盘写一个2G文件,10线程,随机读1分钟,给出结果)
fio -filename=/tmp/test_randread -direct=1 -iodepth 1 -thread -rw=randread -ioengine=psync -bs=16k -size=2G -numjobs=10 -runtime=60 -group_reporting -name=mytest
说明:
filename=/dev/sdb1 测试文件名称,通常选择需要测试的盘的data目录。
direct=1 测试过程绕过机器自带的buffer。使测试结果更真实。
rw=randwrite 测试随机写的I/O
rw=randrw 测试随机写和读的I/O
bs=16k 单次io的块文件大小为16k
bsrange=512-2048 同上,提定数据块的大小范围
size=5g 本次的测试文件大小为5g,以每次4k的io进行测试。
numjobs=30 本次的测试线程为30.
runtime=1000 测试时间为1000秒,如果不写则一直将5g文件分4k每次写完为止。
ioengine=psync io引擎使用pync方式
rwmixwrite=30 在混合读写的模式下,写占30%
group_reporting 关于显示结果的,汇总每个进程的信息。
此外
lockmem=1g 只使用1g内存进行测试。
zero_buffers 用0初始化系统buffer。
nrfiles=8 每个进程生成文件的数量。
read 顺序读
write 顺序写
rw,readwrite 顺序混合读写
randwrite 随机写
randread 随机读
randrw 随机混合读写
io总的输入输出量
bw:带宽 KB/s
iops:每秒钟的IO数
runt:总运行时间
lat (msec):延迟(毫秒)
msec: 毫秒
usec: 微秒
顺序读:
fio -filename=/dev/sdb1 -direct=1 -iodepth 1 -thread -rw=read -ioengine=psync -bs=16k -size=2G -numjobs=10 -runtime=60 -group_reporting -name=mytest
随机写:
fio -filename=/dev/sdb1 -direct=1 -iodepth 1 -thread -rw=randwrite -ioengine=psync -bs=16k -size=2G -numjobs=10 -runtime=60 -group_reporting -name=mytest
顺序写:
fio -filename=/dev/sdb1 -direct=1 -iodepth 1 -thread -rw=write -ioengine=psync -bs=16k -size=2G -numjobs=10 -runtime=60 -group_reporting -name=mytest
混合随机读写:
fio -filename=/dev/sdb1 -direct=1 -iodepth 1 -thread -rw=randrw -rwmixread=70 -ioengine=psync -bs=16k -size=2G -numjobs=10 -runtime=60 -group_reporting -name=mytest -ioscheduler=noop
三,实际测试范例:
[root@localhost ~]# fio -filename=/dev/sdb1 -direct=1 -iodepth 1 -thread -rw=randrw -rwmixread=70 -ioengine=psync -bs=16k -size=200G -numjobs=30 -runtime=100 -group_reporting -name=mytest1
mytest1: (g=0): rw=randrw, bs=16K-16K/16K-16K, ioengine=psync, iodepth=1
…
mytest1: (g=0): rw=randrw, bs=16K-16K/16K-16K, ioengine=psync, iodepth=1
fio 2.0.7
Starting 30 threads
Jobs: 1 (f=1): [________________m_____________] [3.5% done] [6935K/3116K /s] [423 /190 iops] [eta 48m:20s] s]
mytest1: (groupid=0, jobs=30): err= 0: pid=23802
read : io=1853.4MB, bw=18967KB/s, iops=1185 , runt=100058msec
clat (usec): min=60 , max=871116 , avg=25227.91, stdev=31653.46
lat (usec): min=60 , max=871117 , avg=25228.08, stdev=31653.46
clat percentiles (msec):
| 1.00th=[ 3], 5.00th=[ 5], 10.00th=[ 6], 20.00th=[ 8],
| 30.00th=[ 10], 40.00th=[ 12], 50.00th=[ 15], 60.00th=[ 19],
| 70.00th=[ 26], 80.00th=[ 37], 90.00th=[ 57], 95.00th=[ 79],
| 99.00th=[ 151], 99.50th=[ 202], 99.90th=[ 338], 99.95th=[ 383],
| 99.99th=[ 523]
bw (KB/s) : min= 26, max= 1944, per=3.36%, avg=636.84, stdev=189.15
write: io=803600KB, bw=8031.4KB/s, iops=501 , runt=100058msec
clat (usec): min=52 , max=9302 , avg=146.25, stdev=299.17
lat (usec): min=52 , max=9303 , avg=147.19, stdev=299.17
clat percentiles (usec):
| 1.00th=[ 62], 5.00th=[ 65], 10.00th=[ 68], 20.00th=[ 74],
| 30.00th=[ 84], 40.00th=[ 87], 50.00th=[ 89], 60.00th=[ 90],
| 70.00th=[ 92], 80.00th=[ 97], 90.00th=[ 120], 95.00th=[ 370],
| 99.00th=[ 1688], 99.50th=[ 2128], 99.90th=[ 3088], 99.95th=[ 3696],
| 99.99th=[ 5216]
bw (KB/s) : min= 20, max= 1117, per=3.37%, avg=270.27, stdev=133.27
lat (usec) : 100=24.32%, 250=3.83%, 500=0.33%, 750=0.28%, 1000=0.27%
lat (msec) : 2=0.64%, 4=3.08%, 10=20.67%, 20=19.90%, 50=17.91%
lat (msec) : 100=6.87%, 250=1.70%, 500=0.19%, 750=0.01%, 1000=0.01%
cpu : usr=1.70%, sys=2.41%, ctx=5237835, majf=0, minf=6344162
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=118612/w=50225/d=0, short=r=0/w=0/d=0
Run status group 0 (all jobs):
READ: io=1853.4MB, aggrb=18966KB/s, minb=18966KB/s, maxb=18966KB/s, mint=100058msec, maxt=100058msec
WRITE: io=803600KB, aggrb=8031KB/s, minb=8031KB/s, maxb=8031KB/s, mint=100058msec, maxt=100058msec
Disk stats (read/write):
sdb: ios=118610/50224, merge=0/0, ticks=2991317/6860, in_queue=2998169, util=99.77%
主要查看以上红色字体部分的iops
这个文档是对fio-2.0.9 HOWTO文档的翻译,fio的参数太多了,翻译这个文档时并没有测试每一个参数的功能和使用方法,只有少量参数做了试验,大部分的参数采用的是根据字面翻译或是个人理解的翻译,必然有些出入,先发出来,以后有使用的时候再被充和修改。在另一个文档中会对fio自带的实例进行分析,可能会更为清晰一些。
fio这个工具实在太强大了,列举一下他的NB之处吧
1)支持十几种存储引擎,可以自定义
2)自带做图工具,调用gnuplot做图
3)支持几乎所有的存储描述参数
4)大量对CPU,内存,进程/线程,文件,IO特性的配置
5)压缩,trace回放,。。。这些都包含,灵活的配置
简介
fio最初是用来节省为特定负载写专门测试程序,或是进行性能测试,或是找到和重现bug的时间。写这么一个测试应用是非常浪费时间的。因此需要一个工具来模拟给定的io负载,而不用重复的写一个又一个的特定的测试程序。但是test负载很难定义。因为可能会产生很多进程或线程,他们每一个都用他们自己的方式产生io。fio需要足够灵活得来模拟这些case。
典型的fio的工作过程
1)写一个job文件来描述要访真的io负载。一个job文件可以控制产生任意数目的线程和文件。典型的job文件有一个global段(定义共享参数),一个或多少job段(描述具体要产生的job)。
2)运行时,fio从文件读这些参数,做处理,并根据这些参数描述,启动这些访真线程/进程
运行fio
运行方式:
$fio job_file
它会根据job_file的内容来运行。你可以在命令行中指定多个job file,fio进串行化运行这些文件。相当于在同一个job file不同的section之间使用了stonewall参数。
如果某个job file只包含一个job,可以在命令行中给出参数,来直接运行,不再需要读取job file。命令行参数同job file参数的格式是一样的。比如,在job file中的参数iodepth=2,在命令行中可以写为–iodepth 2 或是 –iodepth=2.
fio不需要使用root来支行,除非使用到的文件或是设备需要root权限。一些选项可能会被限制,比如内存锁,io调度器切换,或是nice value降级。
job文件格式
job file格式采用经典的ini文件,[]中的值表示job name,可以采用任意的ASCII字符,‘global’除外,global有特殊的意义。Global section描述了job file中各个job的默认配置值。一个job section可以覆盖global section中的参数,一个job file可以包含几个global section.一个job只会受到它上面的global section的影响。‘;’和‘#’可以用作注释
两个进程,分别从一个从128MB文件中,随机读的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.
上一个实例的说明:采用async,每一个文件的队列长度为4,采用随机写,采用32k的块,采用非direct io,共有4个进程,每个进程随机写64M的文件。也可以采用下面的命令
$fio –name=random-writers –ioengine=libaio –iodepth=4 –rw=randwrite –bs=32k –direct=0 –size=64m –numjobs=4
环境变量
在job file中支持环境变量扩展。类似于${VARNAME}可以作为选项的值(在=号右边)。
实例:
$SIZE=64m NUMJOBS=4 fio jobfile,fio
;–start job files–
[random-writers]
rw=randwrite
size=${SIZE}
numjobs=${NUMJOBS}
;–end job file–
将被扩展为
;–start job file–
[random-writers]
rw=randwrite
size=64m
numjobs=4
;–end job file–
保留keywords
fio有一些保留keywords,在内部将其替换成合适的值,这些keywords是:
$pagesize 当前系统的页大小
$mb_memory 系统的总内存的大小,以MB为单位
$ncpus 在线有效的cpu数
这引起在命令行中和job file中都可以用,当job运行的时候,会自动的用当前系统的徝进行替换。支持简单的数学计算,如:
size=8*$mb_memory
类型
str 字符串
time时间(int)
int 整数
bool
irange 整数范围
float_list 符点数列
一个job包含的基本的参数
1)IO类型
向文件发起的IO类型。
<1>readwrite=str,rw=str
read 顺序读
write 顺序写
randwrite 随机写
randread 随机读
rw,readwrite 顺序混合读写
randrw 随机混合读写
[参数备注]
对于混合io类型,混认是50%的读,50%的写,对于特定的io类型,因为速度可能不同,结果可能会有稍有偏差.
通过在在str之后加“:<nr>”可以配置在执行一下获取offset操作之前要执行的IO次数。For a random read, it would lik ‘rw=randread:8′ for passing in an offset modifier with a value of 8.如果后缀用于顺序IO类型的话,,那么将在每次IO之后,将这个值加到产生的offset之后。e.g. rw=write:4k每次写之后将会跳过4K。它将顺序的IO转化为带有洞的顺序IO。参考‘rw_sequencer’选项。
<2>rw_sequencer=str
如果rw=<str>后有offset修饰的话,这个选项可以控制这个数字<nr>如何修饰产生的IO offset.可以接收的值是:
sequential 产生顺序的offset
identical 产生相同的offset
[参数备注]
‘sequential’仅用于随机IO。通常情况下,fio在每次IO之后,将会生成一个新的随机IO。e.g.rw=randread:8,将会在每8次IO之后执行seek,而不是每次IO之后。顺序IO已经是顺序的,再设置为‘sequential’将不会产生任何不同。‘identical’会产生同‘sequential’相似的行为,只是它会连续产生8次相同的offset,然后生成一个新的offset.
2)block size
产生的IO单元的大小,可以是一个孤立的值,也可以是一个范围。
<1>blocksize=int,bs=int
单次IO的block size,默认为4k。如果是单个值的话,将会对读写都生效。如果是一个逗号,再跟一个int值的话,则是仅对于写有效。也就是说,格式可以是bs=read_end_write或是bs=read,write。e.g. bs=4k,8k读使用4k的块,写使用8k的块。e.g.bs=,8k将使得写采用8k的块,读采用默认的值。
3)IO size
将会读/写多少数据
<1>size=int
这个job IO总共要传输的数据的大小。FIO将会执行到所有的数据传输完成,除非设定了运行时间(‘runtime’选项)。除非有特定的‘nrfiles’选项和‘filesize’选项被设置,fio将会在job定义的文件中平分这个大小。如果这个值不设置的话,fio将会使用这个文件或设备的总大小。如果这些文件不存在的话,size选项一定要给出。也可以给出一个1到100的百分比。e.g. size=20%,fio将会使用给定的文件或设备的20%的空间。
4)IO引擎
发起IO的方式。
<1>ioengine=str
定义job向文件发起IO的方式
sync 基本的read,write.lseek用来作定位
psync 基本的pread,pwrite
vsync 基本的readv,writev
libaio Linux专有的异步IO。Linux仅支持非buffered IO的队列行为。
posixaio glibc posix异步IO
solarisaio solaris独有的异步IO
windowsaio windows独有的异步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周期.e.g. cpuload=85将使用job不做任何的实际IO,但要占用85%的CPU周期。在SMP机器上,使用numjobs=<no_of_cpu>来获取需要的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引擎
5)IO depth
如果IO引擎是异步的,这个指定我们需要保持的队列深度
<1>iodepth=int
加于文件之上的保持的IO单元。默认对于每个文件来说是1,可以设置一个更大的值来提供并发度。iodepth大于1不会影响同步IO引擎(除非verify_async这个选项被设置)。even async engines may impose OS restrictions causing the desired depth not to be achieved.这会在Linux使用libaio并且设置direct=1的时候发生,因为buffered io在OS中不是异步的。在外部通过类似于iostat这些工具来观察队列深度来保证这个IO队列深度是我们想要的。这个可以参考褚霸的博客http://blog.yufeng.info/archives/2104
6)IO type
<1>direct=bool
true,则标明采用non-buffered io.同O_DIRECT效果一样。ZFS和Solaris不支持direct io,在windows同步IO引擎不支持direct io
<2>buffered=bool
true,则标明采用buffered io。是direct的反义词,默认是true
7)Num files
负载将分发到几个文件之中
<1>nrfiles=int
用于这个job的文件数目,默认为1
<2>openfiles=int
在同一时间可以同时打开的文件数目,默认同nrfiles相等,可以设置小一些,来限制同时打开的文件数目。
8)Num threads
<1>numjobs=int
创建特定数目的job副本。可能是创建大量的线程/进程来执行同一件事。我们将这样一系列的job,看作一个特定的group