参考
- https://blog.csdn.net/qq_14935437/article/details/93749444
- https://www.cnblogs.com/cloudphoenix/p/6542909.html
命令清单:
- dd 简单测试
- fio 性能测试
- Iostat 状态监控
FIO 命令
1. FIO 样例
#100%随机,100%读, 4K
fio -filename=/dev/emcpowerb -direct=1 -iodepth 1 -thread -rw=randread -ioengine=psync -bs=4k -size=1000G -numjobs=50 -runtime=180 -group_reporting -name=rand_100read_4k
# 100%随机,100%写, 4K
fio -filename=/dev/emcpowerb -direct=1 -iodepth 1 -thread -rw=randwrite -ioengine=psync -bs=4k -size=1000G -numjobs=50 -runtime=180 -group_reporting -name=rand_100write_4k
#100%顺序,100%读 ,4K
fio -filename=/dev/emcpowerb -direct=1 -iodepth 1 -thread -rw=read -ioengine=psync -bs=4k -size=1000G -numjobs=50 -runtime=180 -group_reporting -name=sqe_100read_4k
#100%顺序,100%写 ,4K
fio -filename=/dev/emcpowerb -direct=1 -iodepth 1 -thread -rw=write -ioengine=psync -bs=4k -size=1000G -numjobs=50 -runtime=180 -group_reporting -name=sqe_100write_4k
#100%随机,70%读,30%写 4K
fio -filename=/dev/emcpowerb -direct=1 -iodepth 1 -thread -rw=randrw -rwmixread=70 -ioengine=psync -bs=4k -size=1000G -numjobs=50 -runtime=180 -group_reporting -name=randrw_70read_4k
2. FIO 参数:
基本说明:
filename=/dev/sdb1 测试文件名称,通常选择需要测试的盘的data目录。
direct=1 是否使用directIO,测试过程绕过OS自带的buffer,使测试磁盘的结果更真实。Linux读写的时候,内核维护了缓存,数据先写到缓存,后面再后台写到SSD。读的时候也优先读缓存里的数据。这样速度可以加快,但是一旦掉电缓存里的数据就没了。所以有一种模式叫做DirectIO,跳过缓存,直接读写SSD。
rw=randwrite 测试随机写的I/O
rw=randrw 测试随机写和读的I/O
bs=16k 单次io的块文件大小为16k
bsrange=512-2048 同上,提定数据块的大小范围
size=5G 每个线程读写的数据量是5GB。
numjobs=1 每个job(任务)开1个线程,这里用了几,后面每个用-name指定的任务就开几个线程测试。所以最终线程数=任务数(几个name=jobx)* numjobs。
name=job1: 一个任务的名字,重复了也没关系。如果fio -name=job1 -name=job2,建立了两个任务,共享-name=job1之前的参数。-name之后的就是job2任务独有的参数。
thread 使用pthread_create创建线程,另一种是fork创建进程。进程的开销比线程要大,一般都采用thread测试。
runtime=1000 测试时间为1000秒,如果不写则一直将5g文件分4k每次写完为止。
ioengine=libaio 指定io引擎使用libaio方式。(IO引擎共13种)
可选方式:
-ioengine=psync -iodepth=1(同步)
-ioengine=libaio -iodepth=4/8/16/1024(异步)
详解 :
libaio方式:Linux本地异步I/O。
请注意,Linux可能只支持具有非缓冲I/O的排队行为(设置为“direct=1”或“buffered=0”);rbd:通过librbd直接访问CEPH Rados
psync方式:如果要使用libaio引擎,需要yum install libaio-devel包
iodepth=16 队列的深度为16.在异步模式下,CPU不能一直无限的发命令到SSD。比如SSD执行读写如果发生了卡顿,那有可能系统会一直不停的发命令,几千个,甚至几万个,这样一方面SSD扛不住,另一方面这么多命令会很占内存,系统也要挂掉了。这样,就带来一个参数叫做队列深度。
Block Devices(RBD) 无需使用内核RBD驱动程序(rbd.ko)。该参数包含很多ioengine,如:libhdfs/rdma等
rwmixwrite=30 在混合读写的模式下,写占30%
group_reporting 关于显示结果的,汇总每个进程的信息。
此外
lockmem=1g 只使用1g内存进行测试。
zero_buffers 用0初始化系统buffer。
nrfiles=8 每个进程生成文件的数量。
磁盘读写常用测试点:
1. Read=100% Ramdon=100% rw=randread (100%随机读)
2. Read=100% Sequence=100% rw=read (100%顺序读)
3. Write=100% Sequence=100% rw=write (100%顺序写)
4. Write=100% Ramdon=100% rw=randwrite (100%随机写)
5. Read=70% Sequence=100% rw=rw, rwmixread=70, rwmixwrite=30
(70%顺序读,30%顺序写)
6. Read=70% Ramdon=100% rw=randrw, rwmixread=70, rwmixwrite=30
重要参数
- IO type: I/O 类型,Read Write 。例如:rw=randwrite。包括:
Read 顺序读 、Write 顺序写 、 RandWrite 随机写、RandRead 随机读。
-
Block Size: 测试工具向被测设备发出的读写数据块的大小,可以是一个单独的值,也可以是一个范围。例如:blocksize=4k。
- 4K 是主流,
- 8K 是 Mysql和 Oracle
- 16K 是 MysqlInnodb。 -
IO engine: I/O 引擎,处理 IO 的方式,定义了发起 IO 的方式,可以是内存映射文件,可以是使用普通的读/写,我们可以使用
- splice,异步 IO,
- syslet,甚至 SG(SCSI generic sg) 。包括 sync,pync,vsync,libaio 等,目前使用最广泛的是 libaio。
- Sync:基本的read,write。通过lseek来作定位;
- Psync:基本的pread,pwrite,在文件描述符给定的位置偏移上读取或写入数据,pread() 从文件 fd 指定的偏移 offset (相对文件开头) 上读取 count 个字节到buf 开始位置。文件当前位置偏移保持不变。 pwrite() 把缓存区 buf 开头的 count个字节写入文件描述符 fd offset 偏移位置上,文件偏移没有改变。 fd 引用的文件必须是可定位的,属于同步I/O;
- Vsync:基本的 readv, writev;
- Libaio: Linux 专有的异步 IO,Linux 仅支持非 buffered IO 的队列行为;
注意:同步和异步的区别:
- 【同步 IO】 是指,进程触发 IO 操作后,后面的操作不能进行,只能等待 IO 操作完成或者放弃 IO 操作,保证当前只有一个 IO 操作在进行。
- 【异步 IO】 是指,触发 IO 操作以后,直接返回,可以继续执行后面的操作,IO 交给内核来处理,完成后内核通知进程 IO 完成。
libaio 引擎会用这个 iodepth 值来调用 io_setup,准备可以一次提交iodepth 个 IO 的上下文,同时申请iodepth个 io 请求队列用于保持 IO。在压测进行的时候,系统会生成特定的 IO 请求,往 io 请求队列里面提交,当队列里面的IO个数达到 iodepth_batch值的时候,就调用 io_submit 批次提交请求,然后开始调用 io_getevents 开始收割已经完成的 IO。每次收割多少呢?由于收割的时候,超时时间设置为 0,所以有多少已完成的 IO 就收割多少,最多可以收割 iodepth_batch_complete 个 IO。随着收割,IO 队列里面的 IO 数就少了,那么需要补充新的 IO。什么时候补充呢?当 IO 数目降到 iodepth_low 值的时候,就重新填充,保证 OS 可以看到至少 iodepth_low 数目的 io 在电梯口排队着。
libaio,这个是追求 IOPS 的;对于延时为主的测试,建议使用 psync。
-
IO size: 总共要读写的数据大小。例如:size=200G
-
IO depth: 测试的队列深度,队列深度表示控制器可同时发送给被测设备的指令数目。在 ATA 指令集的 Read/Write FP DMA Queue 指令中,可以给每个读写指令带上标签。当队列深度为1时,控制器需要等待被测设备完成指令并返回结果后才可执行下一条指令;当队列深度大于 1 时,控制器可以向被测设备发出多条指令,并给每个指令附带一个标签作为指令号,此时被测设备并不按照指令号的顺序返回结果,从而可根据自身 Firmware 算法进行优化,寻找最容易得到的结果并反馈给控制器。当某一条指令的结果返回之后,该标签被回收并可再次利用。针对 SATA硬盘或 SSD,需要控制器工作在 AHCI 模式并且操作系统加载 AHCI 驱动程序且被测设备本身要支持 NCQ 才能支持此种访问模式。按照上述原理,在队列深度增加时,被测设备的访问效率将有明显提升,故性能也有相应提升。 默认对于每个文件来说是 1,可以设置一个更大的值来提高并发度。例如:iodepth=1
-
IO type: 表示我们将执行 buffered io 还是 direct/raw io。 ZFS 和 Solaris 不支持direct io,在 windows 上同步 IO 引擎不支持 direct io。 Direct=0 时,则表明采用 buffered io。例如:direct=1
-
Num files: 表示负载将分发到几个文件中。例如:nrfiles=8
-
Num threads: 创建多少个进程/线程来并发执行。例如:numjobs=1。numjobs 建议等于 CPU 的 core 值,即 HT=off。
-
Runtime: 测试运行时间。例如:runtime=30
-
数据填充方式: 当进行数据写入时,可选择写入数据的形式。此选项可选三种模式,分别为重复填充、伪随机填充、随机填充。重复填充表示全 0 的数据写入,当 SSD主控支持数据压缩功能时,大量的全 0 数据将以压缩的方式写入 SSD 从而显著提高性能;伪随机填充写入即为伪随机数的填充写入,由于生成随机数需要花费大量时间,故在通常测试中,为减少等待时间,一般选择伪随机数填充。在选择伪随机数写入后,SSD 主控即使支持数据压缩功能也不能够对伪随机数进行压缩;全随机填充即为先进行随机数生成,之后再进行写入。随机数生成会消耗大量时间,通常测试中不采用此种模式。例如:refill_buffers
-
percentage_random: 随机和顺序比率;例如:percentage_random=80,80%的随机。
-
time_based : 决定脚本的运行时间,即使 file 已被完全读写或写完,也要执行完runtime 规定的时间。它是通过循环执行相同的负载来实现的。例如:time_based。
-
目标盘符/被测盘符:当需要测试多个磁盘时,需要增加多行以下内容,例如: filename=/dev/sdb; 如果写在配置文件中,则需创建多个job区分多个不同的测试目标设备;
3. FIO 引擎
FIO支持 13种不同的 I/O 引擎, 包括:sync, mmap, libaio, posixaio, SG v3, splice, null, network,syslet,guasi,solarisaio 等等。 FIO 的引擎能识别简单易懂的job file文本去进行测试,同时能提供各种 I/O 性能指标,如I/O 延迟、IOPS和带宽等。因此被大量的制造商和广泛的用户认可,作为确认IO系统良好的测试工具。
4. FIO 执行结果解读:
结果解读:
结果解读:
test: (g=0): rw=write, bs=1M-1M/1M-1M/1M-1M, ioengine=libaio, iodepth=16
fio-2.8
Starting 1 process
Jobs: 1 (f=1): [W(1)] [100.0% done] [0KB/68198KB/0KB /s] [0/66/0 iops] [eta 00m:00s]
test: (groupid=0, jobs=1): err= 0: pid=4676: Thu Apr 7 17:22:37 2016
write: io=20075MB, bw=68464KB/s, iops=66, runt=300255msec #执行多少IO,平均带宽,线程运行时间
slat (usec): min=51, max=5732, avg=291.11, stdev=262.47 #提交延迟
clat (usec): min=1, max=2235.8K, avg=239043.28, stdev=153384.41 #完成延迟
lat (usec): min=367, max=2235.9K, avg=239337.72, stdev=153389.57 #响应时间
clat percentiles (usec):
| 1.00th=[ 221], 5.00th=[ 442], 10.00th=[ 1004], 20.00th=[108032],
| 30.00th=[228352], 40.00th=[248832], 50.00th=[257024], 60.00th=[268288],
| 70.00th=[280576], 80.00th=[301056], 90.00th=[342016], 95.00th=[477184],
| 99.00th=[806912], 99.50th=[864256], 99.90th=[1122304], 99.95th=[1171456],
| 99.99th=[1646592]
bw (KB /s): min= 170, max=204800, per=100.00%, avg=68755.07, stdev=27034.84
lat (usec) : 2=0.01%, 4=0.13%, 50=0.06%, 100=0.26%, 250=1.04%
lat (usec) : 500=4.53%, 750=2.61%, 1000=1.33%
lat (msec) : 2=1.18%, 4=0.15%, 10=0.77%, 20=0.77%, 50=1.50%
lat (msec) : 100=4.43%, 250=23.48%, 500=53.23%, 750=3.09%, 1000=1.30%
lat (msec) : 2000=0.19%, >=2000=0.01%
cpu : usr=0.03%, sys=2.11%, ctx=19066, majf=0, minf=7
IO depths : 1=0.1%, 2=0.1%, 4=0.1%, 8=0.1%, 16=103.8%, 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%
issued : total=r=0/w=20060/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):
WRITE: io=20075MB, aggrb=68464KB/s(group总带宽), minb=68464KB/s(最小平均带宽), maxb=68464KB/s(最大平均带宽), mint=300255msec(group中线程的最短运行时间), maxt=300255msec(group中线程的最长运行时间)
Disk stats (read/write):
sda: ios=23/41769(所有group总共执行的IO数), merge=0/149(总共发生的IO合并数), ticks=706/9102766(Number of ticks we kept the disk busy), in_queue=9105836(花费在队列上的总共时间), util=100.00%(磁盘利用率)
io=执行了多少M的IO
bw=平均IO带宽
iops=IOPS
runt=线程运行时间
slat=提交延迟,提交该IO请求到kernel所花的时间(不包括kernel处理的时间)
clat=完成延迟, 提交该IO请求到kernel后,处理所花的时间
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=磁盘利用率
io=执行了多少M的IO
bw=平均IO带宽
iops=IOPS
runt=线程运行时间
slat=提交延迟,提交该IO请求到kernel所花的时间(不包括kernel处理的时间)
clat=完成延迟, 提交该IO请求到kernel后,处理所花的时间
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=磁盘利用率