fio(Flexible I/O Tester)正是非常常用的文件系统和磁盘 I/O 性能基准测试工具。提供了大量的可定制化选项,可以用来测试,裸盘、一个单独的分区或者文件系统在各种场景下的 I/O 性能,包括了不同块大小、不同 I/O 引擎以及是否使用缓存等场景。
ubuntu安装fio非常简单
root@nvme:~# apt install -y fio
fio选项比较多,可以通过man fio查看,下面是比较常用的几个参数及说明
- direct,表示是否跳过系统缓存,1表示跳过系统缓存。
- iodepth,表示使用异步 I/O(asynchronous I/O,简称 AIO,ioengine=libaio)时,同时发出的 I/O 请求上限。
- rw,表示 I/O 模式。read/write 分别表示顺序读 / 写,而 randread/randwrite 则分别表示随机读 / 写,randrw配合rwmixwrite分别表示混合测试及写占比。
- ioengine,表示 I/O 引擎,它支持同步(sync)、异步(libaio)、内存映射(mmap)、网络(net)等各种 I/O 引擎
- bs,表示 I/O 的大小。默认值是4KiB
- filename,表示文件路径,可以是磁盘路径(测试磁盘性能),也可以是文件路径(测试文件系统性能)
-
size,寻址空间,IO会落在 [0, size)这个区间的硬盘空间上。这是一个可以影响IOPS的参数。一般设置为硬盘的大小
-
runtime,运行时间
-
numjobs,并行job数,默认1
-
group_reporting,聚合job的测试结果
四个核心磁盘IO性能指标
介绍完工具,我们来介绍一下IO的性能指标,工具只是直观的给出测试结果,对指标的解读才是评估IO性能的依据,磁盘I/O的核心指标包括,
使用率,是指磁盘忙处理 I/O 请求的百分比
IOPS(Input/Output Per Second),是指每秒的 I/O 请求数
吞吐量,是指每秒的 I/O 请求大小
响应时间,是指从发出 I/O 请求到收到响应的间隔时间
如果孤立的看通过工具得来的指标数据是没有意义的,也就是说一定要结合场景及硬件特性来观测指标数据,如我的测试环境金士顿NVME SSD盘(下图截自金士顿官网)明确标出读/写速度3500MB/秒和2100MB/秒(MB=10^6)
先来一个read测试
- # fio job文件nread.fio
- root@nvme:~/fio# cat nread.fio
- [global]
- bs=4096
- rw=read
- ioengine=libaio
- size=50G
- direct=1
- iodepth=256
- iodepth_batch=128
- iodepth_low=128
- iodepth_batch_complete=128
- userspace_reap
- group_reporting
- [test]
- numjobs=1
- filename=/dev/nvme0n1
-
- # 执行测试及输出结果
- root@nvme:~/fio# fio nread.fio
- test: (g=0): rw=read, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=libaio, iodepth=256
- fio-3.28
- Starting 1 process
- Jobs: 1 (f=1): [R(1)][100.0%][r=2908MiB/s][r=744k IOPS][eta 00m:00s]
- test: (groupid=0, jobs=1): err= 0: pid=1509: Wed May 10 12:54:46 2023
- read: IOPS=728k, BW=2842MiB/s (2980MB/s)(50.0GiB/18015msec)
- slat (usec): min=70, max=856, avg=91.24, stdev= 9.05
- clat (usec): min=60, max=20044, avg=247.35, stdev=100.53
- lat (usec): min=159, max=20901, avg=338.61, stdev=102.93
- clat percentiles (usec):
- | 1.00th=[ 149], 5.00th=[ 194], 10.00th=[ 200], 20.00th=[ 212],
- | 30.00th=[ 225], 40.00th=[ 231], 50.00th=[ 237], 60.00th=[ 245],
- | 70.00th=[ 258], 80.00th=[ 273], 90.00th=[ 302], 95.00th=[ 347],
- | 99.00th=[ 433], 99.50th=[ 457], 99.90th=[ 537], 99.95th=[ 570],
- | 99.99th=[ 668]
- bw ( MiB/s): min= 2383, max= 2914, per=100.00%, avg=2843.14, stdev=134.15, samples=36
- iops : min=610048, max=745984, avg=727843.56, stdev=34342.08, samples=36
- lat (usec) : 100=0.14%, 250=64.34%, 500=35.33%, 750=0.19%, 1000=0.01%
- lat (msec) : 20=0.01%, 50=0.01%
- cpu : usr=12.67%, sys=54.62%, ctx=114337, majf=0, minf=268
- IO depths : 1=0.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=100.0%
- submit : 0=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=100.0%
- complete : 0=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=100.0%
- issued rwts: total=13107200,0,0,0 short=0,0,0,0 dropped=0,0,0,0
- latency : target=0, window=0, percentile=100.00%, depth=256
-
- Run status group 0 (all jobs):
- READ: bw=2842MiB/s (2980MB/s), 2842MiB/s-2842MiB/s (2980MB/s-2980MB/s), io=50.0GiB (53.7GB), run=18015-18015msec
-
- Disk stats (read/write):
- nvme0n1: ios=203471/0, merge=12818862/0, ticks=54295/0, in_queue=54295, util=99.48%
测试结果分析,分别使用iodepth=256、128、64、32、16、8进行测试,iodepth=256、iodepth_batch=128、iodepth_low=128、iodepth_batch_complete=128这一组参数结果最好,顺序读吞吐量(BW)峰值接近3000MB,距离厂商3500MB/秒的读速率稍有差距,差距在哪里呢?Linux内核NVME驱动为了其通用性和冗长的IO栈,并不能完全发挥其硬件性能,所以当下如SPDK等绕过内核的用户态NVME驱动已成为高性能存储首选技术方案,后续spdk文章会结束相关内容
iodepth_batch(等同于iodepth_batch_submit),批次提交,默认1,即立即提交
iodepth_low(low water mark,队列低于此值时开始填充队列),默认等于iodepth,fio总是尝试保持IO队列状态为满
iodepth_batch_complete(等同于iodepth_batch_complete_min),默认1,即有完成IO立即处理,该参数可以reduce latency
这几个参数对结果影响很大,详见man fio
除了iops、BW、latency几个主要IO指标外,需要注意latency的min、max、stdev数据,如果数据相对离散也就是stdev值异常,说明IO性能有可能出现长尾,此外还应该注意clat percentiles累积直方图数据,关于累积直方图,可以参考Promethues的HISTOGRAMS AND SUMMARIES
IO队列
fio测试,iodepth相关几个参数对测试结果影响非常明显,256为什么会稳定好于128,128则稳定好于64呢?
- root@nvme:~# lsscsi -lll
- [1:0:0:0] disk ATA ST2000DM008-2FR1 0001 /dev/sda
- device_blocked=0
- iocounterbits=32
- iodone_cnt=0x2d0b
- ioerr_cnt=0x25
- iorequest_cnt=0x2f1f
- queue_depth=32
- queue_type=simple
- scsi_level=6
- state=running
- timeout=30
- type=0
- [N:0:1:1] disk KINGSTON SNV2S1000G__1 /dev/nvme0n1
- capability=40
- ext_range=256
- hidden=0
- nsid=1
- range=0
- removable=0
- nr_requests=255
- read_ahead_kb=128
- write_cache=write back
- logical_block_size=512
- physical_block_size=512
-
-
- # 或通过sysfs查看nvme0n1 device的队列深度
- root@nvme:~/fio# cat /sys/devices/pci0000\:00/0000\:00\:1b.0/0000\:02\:00.0/nvme/nvme0/nvme0n1/queue/nr_requests
- 255
- root@nvme:~/fio#
无论是通过lsscsi -l还是通过sysfs查看,nvme0n1的队列深度是256,再次运行fio,同时打开iostat -x 2观测nvme设备队列相关指标数据
- Device r/s rkB/s rrqm/s %rrqm r_await rareq-sz w/s wkB/s wrqm/s %wrqm w_await wareq-sz d/s dkB/s drqm/s %drqm d_await dareq-sz f/s f_await aqu-sz %util
- loop5 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
- nvme0n1 5286.00 1353216.00 333031.00 98.44 0.33 256.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 1.75 100.00
- sda 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
通过测试发现,当rw=read时,iostat输出rareq-sz几乎稳定等于256,而当rw=write时,wareq-sz稳定等于256,而增加iodepth至更大时fio和iostat指标数据都几乎无变化,但是减小时iops、BW等数据均会减少
通过SATA盘再次验证则数据变化不明显
另外,对于顺序读写,numjobs=1(IOPS=728k, BW=2842MiB/s)能够获得最好的收益(指标数据最好),numjobs增加时,指标数据会线性减少,当numjob=2(IOPS=393k, BW=1536MiB/s)、numjob=4(IOPS=400k, BW=1562MiB/s)、numjob=8(IOPS=366k, BW=1430MiB/s)
混合随机读写(读写比例80/20)
随机读写不同于顺序读写,混合随机读写场景更加贴近于真实场景,iops和BW都要小的多,测试如下,调整iodepth及numjobs测试结果见下表:
- [global]
- bs=4096
- rw=randrw
- rwmixwrite=20
- ioengine=libaio
- direct=1
- group_reporting
- iodepth=32
- iodepth_batch=8
- iodepth_low=8
- iodepth_batch_complete=8
- userspace_reap
- runtime=60
- [test]
- numjobs=16
- filename=/dev/nvme0n1
iodepth/_low/_batch/_complete | numjobs | iops(read) | bw(read) | iops(write) | bw(write) |
16/8/8/8 | 8 | 23.8k | 93.1MiB/s | 5968 | 23.3MiB/s |
32/8/8/8 | 1 | 15.4k | 60.3MiB/s | 3865 | 15.1MiB/s |
32/8/8/8 | 8 | 37.9k | 148MiB/s | 9500 | 37.1MiB/s |
32/8/8/8 | 16 | 40.4k | 158MiB/s | 10.1k | 39.5MiB/s |
32/16/16/16 | 16 | 40.5k | 158MiB/s | 10.1k | 39.5MiB/s |
64/32/32/32 | 16 | 40.4k | 158MiB/s | 10.1k | 39.5MiB/s |
64/16/16/16 | 1 | 22.6k | 88.4MiB/s | 5660 | 22.1MiB/s |
64/16/16/16 | 64 | 42.8k | 167MiB/s | 10.7k | 41.8MiB/s |
numjobs增加不是免费的,top观测fio所占物理内存线性增加,而最后numjobs=64 iodepth=64测试,综合iostat数据,w_await、r_await、aqu_sz都明显增加,混合随机读写场景下,相比于iodepth,numjobs更能影响IO性能
欢迎转载,请说明出处