linux-fio-磁盘-性能测试

我们最常用的磁盘性能评价指标主要有两个:IOPS和吞吐量。IOPS是Input/Output Per Second的缩写,它表示单位时间内系统能处理的I/O请求数量,即每秒钟系统能处理的读写次数。吞吐量衡量单位时间内系统能处理的数据的体量,即每秒钟磁盘上能读写出的数据量的大小,通常以kB/s或MB/s为单位。

两个指标相互独立又相互关联,在不同业务场景下,侧重关注的指标也有所不同。

举例说明

举个例子来说明这两个指标。磁盘IO就相当于餐馆端餐员从后厨端菜到餐厅,然后由上菜员上菜的过程。托盘的大小,决定了一次最多可以上多少盘菜(数据量)。
一次上菜的过程就相当于一次数据IO请求,端菜员从后厨接菜上菜盘,餐厅接菜员给客户上菜,就是磁盘对IO的读写处理。在端菜员和上菜员数量固定且上菜速度(磁盘数据处理速度)一致的情况下,如果餐厅放置菜盘的托盘有大小之分,那么上菜时用小的托盘肯定比用大的托盘完成上菜的速度肯定快,时间耗时更短(寻找餐桌的时间少,磁盘寻址时间短),但单次菜盘数(吞吐量)较少。

所以在做磁盘性能测试的时候,往往一次只关注一个指标,追求IOPS,就用小托盘端少份数的菜,分多次配送, 会增加寻址时间(需要准备把每盘菜送达准备餐桌)。追求吞吐量,就用大托盘,一次端多份数的菜,节省往来后厨和餐厅的时间(寻址时间)。

测试影响因素

实际测量中,IOPS会受到很多因素的影响

数据块大小

相当于我们前面说的大托盘和小托盘端菜的情况

顺序和随机

顺序就是我们的菜都是按桌上的,随机则表示一个托盘的菜是多个餐桌拥有,那寻找餐桌就比较耗时(寻址时间)。

队列深度

如果只有一个端餐员,那么当端餐员在后厨端菜或者送往餐厅过程中,所有的上菜员都处于等待状态。作为酒店老板,肯定不想看到这种情况,肯定希望上菜员(磁盘)一直处于工作状态,从而节约成本(提高磁盘性能)。想实现这一点,我们可以增加多个端菜员,保持始终有端菜员与上菜员对接,这样整个上菜过程就一直处于饱和状态。
队列深度就是在后台登上厨师炒菜的端菜员到来往后厨与餐厅的端菜员到与上菜员对接的端菜员的总数。

线程数

测试时,增加线程数也可以增加并发度,从而使上菜员一直处于有工作可做的状态。

读写比例

读操作相当于我们将菜从后厨运送到餐桌就结束了。而写操作意味着把餐桌吃完的空盘收回到后厨。因此不同的读写比例也会造成测试结果的不同。

正是由于这些不同影响因素的存在,我们在对磁盘进行性能测试时,需要仔细选择测试参数,否则将无法测出磁盘的最优性能。同时应将测试参数和方法定性定量,否则测试结果将失去比较的价值。

fio 参数解释

yum install fio libaio-devel

FIO是测试IOPS的非常好的工具,用来对硬件进行压力测试和验证,支持13种不同的I/O引擎,包括:sync,mmap, libaio, posixaio, SG v3, splice, null, network, syslet, guasi, solarisaio 等等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
filename=/dev/emcpowerb 支持文件系统或者裸设备,-filename=/dev/sda2或-filename=/dev/sdb
direct=1 测试过程绕过机器自带的buffer,使测试结果更真实, 异步引擎下起作用,如libaio
rw=randread 测试随机读的I/O
rw=randwrite 测试随机写的I/O
rw=randrw 测试随机混合写和读的I/O
rw=read 测试顺序读的I/O
rw=write 测试顺序写的I/O
rw=rw 测试顺序混合写和读的I/O
bs=4k 单次io的块文件大小为4k
bsrange=512-2048 同上,指定数据块的大小范围
size=5g 本次的测试文件大小为5g,以每次4k的io进行测试
numjobs=30 本次的测试线程为30
runtime=1000 测试时间为1000秒,如果不写则一直将5g文件分4k每次写完为止
ioengine=libaio io引擎使用libaio方式,如果要使用libaio引擎,需要yum install libaio-devel包
rwmixwrite=30 在混合读写的模式下,写占30%
group_reporting 关于显示结果的,汇总每个进程的信息
此外
lockmem=1g 只使用1g内存进行测试
zero_buffers 用0初始化系统buffer
nrfiles=8 每个进程生成文件的数量

IOPS

随机读写频繁的应用,如小文件存储(图片)、OLTP数据库、邮件服务器,关注随机读写性能,IOPS是关键衡量指标。

随机写IOPS

4k 随机写

1
fio -filename=/dev/sdb -direct=1 -iodepth 16 -thread -rw=randwrite -ioengine=libaio -bs=4k -size=5G -numjobs=1 -runtime=1000 -group_reporting -name=mytest

16k 随机写

1
fio -filename=/dev/sdb -direct=1 -iodepth 16 -thread -rw=randwrite -ioengine=libaio -bs=16k -size=5G -numjobs=1 -runtime=1000 -group_reporting -name=mytest

随机读IOPS

4K 随机读

1
fio -filename=/dev/sdb -direct=1 -iodepth 16 -thread -rw=randread -ioengine=libaio -bs=4k -size=1G -numjobs=1 -runtime=1000 -group_reporting -name=mytest

16k 随机读

1
fio -filename=/dev/sdb -direct=1 -iodepth 16 -thread -rw=randread -ioengine=libaio -bs=16k -size=2G -numjobs=1 -runtime=1000 -group_reporting -name=mytest

顺序读IOPS

4k 顺序读

1
fio -filename=/dev/sdb -direct=1 -iodepth 16 -thread -rw=read -ioengine=libaio -bs=4k -size=2G -numjobs=1 -runtime=1000 -group_reporting -name=mytest

16k 顺序读

1
fio -filename=/dev/sdb -direct=1 -iodepth 16 -thread -rw=read -ioengine=libaio -bs=16k -size=4G -numjobs=1 -runtime=1000 -group_reporting -name=mytest

顺序写IOPS

4k 顺序写

1
fio -filename=/dev/sdb -direct=1 -iodepth 16 -thread -rw=write -ioengine=libaio -bs=4k -size=2G -numjobs=1 -runtime=1000 -group_reporting -name=mytest

16k 顺序写

1
fio -filename=/dev/sdb -direct=1 -iodepth 16 -thread -rw=write -ioengine=libaio -bs=16k -size=5G -numjobs=1 -runtime=1000 -group_reporting -name=mytest

输出结果分析

4k iops 随机写案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# fio -filename=/dev/lun2 -direct=1 -iodepth 16 -thread -rw=randwrite -ioengine=libaio -bs=4k -size=5G -numjobs=1 -runtime=1000 -group_reporting -name=mytest
mytest: (g=0): rw=randwrite, bs=4K-4K/4K-4K/4K-4K, ioengine=libaio, iodepth=16
fio-2.2.8
Starting 1 thread
Jobs: 1 (f=1): [w(1)] [99.2% done] [0KB/57468KB/0KB /s] [0/14.4K/0 iops] [eta 00m:02s]
mytest: (groupid=0, jobs=1): err= 0: pid=28034: Wed Sep 26 15:10:35 2018
write: io=5120.0MB, bw=22220KB/s, iops=5555, runt=235949msec
slat (usec): min=1, max=177, avg=10.52, stdev= 6.33 # 提交延迟
clat (usec): min=76, max=730891, avg=2868.15, stdev=15918.50 # 完成延迟
lat (usec): min=93, max=730897, avg=2878.78, stdev=15918.50 # 响应时间
clat percentiles (usec):
| 1.00th=[ 106], 5.00th=[ 125], 10.00th=[ 149], 20.00th=[ 203],
| 30.00th=[ 235], 40.00th=[ 270], 50.00th=[ 314], 60.00th=[ 382],
| 70.00th=[ 532], 80.00th=[ 1020], 90.00th=[ 2448], 95.00th=[ 5408],
| 99.00th=[79360], 99.50th=[119296], 99.90th=[211968], 99.95th=[254976],
| 99.99th=[358400]
bw (KB /s): min=13376, max=116333, per=99.65%, avg=22142.21, stdev=6438.45 # 带宽
lat (usec) : 100=0.31%, 250=34.47%, 500=33.85%, 750=6.89%, 1000=4.25%
lat (msec) : 2=8.50%, 4=5.23%, 10=3.33%, 20=0.77%, 50=0.79%
lat (msec) : 100=0.91%, 250=0.65%, 500=0.05%, 750=0.01%
cpu : usr=1.34%, sys=7.35%, ctx=907162, majf=0, minf=282 # cpu 利用率
IO depths : 1=0.1%, 2=0.1%, 4=0.1%, 8=0.1%, 16=100.0%, 32=0.0%, >=64=0.0% # IO 队列
submit : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0% # 单个IO提交 要提交的IO数
complete : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.1%, 32=0.0%, 64=0.0%, >=64=0.0% # 单个IO提交 提交成功的IO数
issued : total=r=0/w=1310720/d=0, short=r=0/w=0/d=0, drop=r=0/w=0/d=0
latency : target=0, window=0, percentile=100.00%, depth=16 # IO 完 延迟的分布
Run status group 0 (all jobs):
# io: 总共执行了多少size的IO,aggrb:group总带宽,minb:最小平均带宽,maxb:最大平均带宽
# mint: group中线程的最短运行时间, maxt: group中线程的最长运行时间.
WRITE: io=5120.0MB, aggrb=22220KB/s, minb=22220KB/s, maxb=22220KB/s, mint=235949msec, maxt=235949msec
Disk stats (read/write):
# ios: 所有group总共执行的IO数. merge: 总共发生的IO合并数. ticks: Number of ticks we kept the disk busy
# in_queue: 花费在队列上的总共时间. util: 磁盘利用率
lun2: ios=0/0, merge=0/0, ticks=0/0, in_queue=0, util=0.00%

吞吐量

吞吐量就是把块大小(bs值)调大

写吞吐量

1
fio -filename=/dev/sdb -direct=1 -iodepth 16 -thread -rw=write -ioengine=libaio -bs=1024k -size=1G -numjobs=1 -runtime=1000 -group_reporting -name=mytest

读吞吐量

顺序读写频繁的应用,传输大量连续数据,如电视台的视频编辑,视频点播VOD(Video On Demand),关注连续读写性能。数据吞吐量是关键衡量指标。

1
fio -filename=/dev/sdb -direct=1 -iodepth 16 -thread -rw=read -ioengine=libaio -bs=1024k -size=1G -numjobs=1 -runtime=1000 -group_reporting -name=mytest

iostat查看结果

1
2
3
iostat -dxk 1
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sdb 0.00 0.00 24055.00 0.00 96220.00 0.00 8.00 15.86 0.66 0.66 0.00 0.04 100.00

rrqm/s: 每秒对该设备的读请求被合并次数,文件系统会对读取同块(block)的请求进行合并。

wrqm/s:每秒对该设备的写请求被合并次数。

r/s:每秒读取的次数(IOPS)。

w/s:每秒写入的次数(IOPS)。

rsec/s:每秒读取的扇区数。

wsec/s:每秒写入的扇区数。

rKB/s:每秒读数据量(kB为单位)。

wKB/s︰ 每秒写数据量(kB为单位)。

avgrq-sz:平均每次IO操作的数据量(扇区数为单位)。

avgqu-sz:平均等待处理的IO请求队列长度。

await:每一个IO请求的处理的平均时间(单位是微秒毫秒)。这里可以理解为IO的响应时间,一般地系统IO响应时间应该低于5ms,如果大于10ms就比较大了。

svctm:平均每次IO请求的处理时间(毫秒为单位)。

%util:在统计时间内所有处理IO时间,除以总共统计时间。例如,如果统计间隔1秒,该设备有0.8秒在处理IO,而0.2秒闲置,那么该设备的%util = 0.8/1 = 80%,所以该参数暗示了设备的繁忙程度。一般地,如果该参数是100%表示设备已经接近满负荷运行了(当然如果是多磁盘,即使%util是100%,因为磁盘的并发能力,所以磁盘使用未必就到了瓶颈)。

以上各值之间也存在联系,我们可以由一些值计算出其他数值,例如:

util = (r/s+w/s) * (svctm/1000)

对于上面的例子有:util = (7.8+31.49)*(2.62/1000) = 0.098

参考:磁盘性能压测二三事之——性能参数和指标
使用fio测试SATA盘和SSD盘读写性能