什么是IOPS

IOPS(Input/Output Per Second)即每秒的输入输出量(或读写次数),是衡量磁盘性能的主要指标之一。

IOPS是指单位时间内系统能处理的I/O请求数量,一般以每秒处理的I/O请求数量为单位,I/O请求通常为读或写数据操作请求。

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

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

IOPS和数据吞吐量适用于不同的场合

读取10000个1KB文件,用时10秒 Throught(吞吐量)=1MB/s,IOPS=1000 追求IOPS

读取1个10MB文件,用时0.2秒 Throught(吞吐量)=50MB/s,追求吞吐量

简而言之:

磁盘的IOPS,也就是在一秒内,磁盘进行多少次I/O读写。

磁盘的吞吐量,也就是每秒磁盘I/O的流量,即磁盘写入加上读出的数据的大小。

IOPS计算公式

对于磁盘来说一个完整的IO操作是这样进行的:

当控制器对磁盘发出一个IO操作命令的时候,磁盘的驱动臂(Actuator Arm)带读写磁头(Head)离开着陆区(Landing Zone,位于内圈没有数据的区域),移动到要操作的初始数据块所在的磁道(Track)的正上方,这个过程被称为寻址(Seeking),对应消耗的时间被称为寻址时间(Seek Time);但是找到对应磁道还不能马上读取数据,这时候磁头要等到磁盘盘片(Platter)旋转到初始数据块所在的扇区(Sector)落在读写磁头正上方的之后才能开始读取数据,在这个等待盘片的旋转到可操作性扇区的过程中消耗的时间称为旋转延时(Rotational Delay),接下来就随着盘片的旋转,磁头不断的读/写相应的数据块,直到完成这次IO所需要操作的全部数据,这个过程称为数据传送(Data Transfer),对应的时间称为传送时间(Transfer Time)。完成这三个步骤之后一次IO操作也就完成了。

硬盘IOPS:是指硬盘每秒的读写次数

IO时间(读写时间) = 磁头移动时间 + 磁盘转动时间 +数据处理时间

IO时间(读写时间) = (磁头移动时间 + 60s/转速/2 + IOChunkSize/传输速度)

IOPS = 1000/IO时间

带宽=IOPS*IO大小

常见磁盘平均物理寻道时间

  • 7200转/分的STAT硬盘平均物理寻道时间是9ms
  • 10000转/分的STAT硬盘平均物理寻道时间是6ms
  • 15000转/分的SAS硬盘平均物理寻道时间是4ms

常见硬盘的旋转延迟时间

  • 7200 rpm的磁盘平均旋转延迟大约为601000/7200/2 = 4.17m
  • 10000 rpm的磁盘平均旋转延迟大约为601000/10000/2 = 3ms
  • 15000 rpm的磁盘其平均旋转延迟约为60*1000/15000/2 = 2ms

最大IOPS的理论计算方法

IOPS = 1000 ms/ (寻道时间 + 旋转延迟)。可以忽略数据传输时间。

  • 7200 rpm的磁盘IOPS = 1000 / (9 + 4.17) = 76 IOPS
  • 10000 rpm的磁盘IOPS = 1000 / (6+ 3) = 111 IOPS
  • 15000 rpm的磁盘IOPS = 1000 / (4 + 2) = 166 IOPS

Centos7 测试IOPS方法

# 安装 FIO压测工具
wget http://brick.kernel.dk/snaps/fio-2.0.7.tar.gz
# 若系统无法上网可配置离线yum仓库
# https://chensir.ink/0abec7f652b7/#配置离线yum仓库
yum -y install libaio-devel
tar -zxvf fio-2.0.7.tar.gz
cd fio-2.0.7
make && make install

随机读写测试

# 4k顺序读
fio -filename=/tmp/fiotest -direct=1 -iodepth 1 -thread -rw=read -rwmixread=70 -ioengine=psync -bs=4k -size=5G -numjobs=20 -runtime=60 -group_reporting -name=sqe_100read_4k

# 4k顺序写
fio -filename=/tmp/fiotest -direct=1 -iodepth 1 -thread -rw=write -rwmixread=70 -ioengine=psync -bs=4k -size=5G -numjobs=20 -runtime=60 -group_reporting -name=sqe_100write_4k

# 4k顺序混合读写
fio -filename=/tmp/fiotest -direct=1 -iodepth 1 -thread -rw=rw -rwmixread=70 -ioengine=psync -bs=4k -size=5G -numjobs=20 -runtime=60 -group_reporting -name=sqe_70read_4k

# 4k随机读
fio -filename=/tmp/fiotest -direct=1 -iodepth 1 -thread -rw=randread -rwmixread=70 -ioengine=psync -bs=4k -size=5G -numjobs=20 -runtime=60 -group_reporting -name=rand_100read_4k

# 4k随机写
fio -filename=/tmp/fiotest -direct=1 -iodepth 1 -thread -rw=randwrite -rwmixread=70 -ioengine=psync -bs=4k -size=5G -numjobs=20 -runtime=60 -group_reporting -name=rand_100write_4k

# 4k随机混合读写
fio -filename=/tmp/fiotest -direct=1 -iodepth 1 -thread -rw=randrw -rwmixread=70 -ioengine=psync -bs=4k -size=5G -numjobs=20 -runtime=60 -group_reporting -name=rand_70read_4k

测试脚本

# fiopressure.sh

#!/bin/bash
filename=/tmp/fiotest
size=5G
runtime=60
report_path=/var/log/fio.report
# 4k顺序读
echo ">>>正在进行4k顺序读测试"
fio -filename=$filename -direct=1 -iodepth 1 -thread -rw=read -rwmixread=70 -ioengine=psync -bs=4k -size=$size -numjobs=20 -runtime=$runtime -group_reporting -name=4k顺序读 > $report_path
# 4k顺序写
echo ">>>正在进行4k顺序写测试"
fio -filename=$filename -direct=1 -iodepth 1 -thread -rw=write -rwmixread=70 -ioengine=psync -bs=4k -size=$size -numjobs=20 -runtime=$runtime -group_reporting -name=4k顺序写 >> $report_path
# 4k顺序混合读写
echo ">>>正在进行4k顺序混合读写测试"
fio -filename=$filename -direct=1 -iodepth 1 -thread -rw=rw -rwmixread=70 -ioengine=psync -bs=4k -size=$size -numjobs=20 -runtime=$runtime -group_reporting -name=4k顺序混合读写 >> $report_path
# 4k随机读
echo ">>>正在进行4k随机读测试"
fio -filename=$filename -direct=1 -iodepth 1 -thread -rw=randread -rwmixread=70 -ioengine=psync -bs=4k -size=$size -numjobs=20 -runtime=$runtime -group_reporting -name=4k随机读 >> $report_path
# 4k随机写
echo ">>>正在进行4k随机写测试"
fio -filename=$filename -direct=1 -iodepth 1 -thread -rw=randwrite -rwmixread=70 -ioengine=psync -bs=4k -size=$size -numjobs=20 -runtime=$runtime -group_reporting -name=4k随机写 >> $report_path
# 4k随机混合读写
echo ">>>正在进行4k随机混合读写测试"
fio -filename=$filename -direct=1 -iodepth 1 -thread -rw=randrw -rwmixread=70 -ioengine=psync -bs=4k -size=$size -numjobs=20 -runtime=$runtime -group_reporting -name=4k随机混合读写 >> $report_path
echo ">>>FIO测试完毕,测试报告位于$report_path"

参数说明

# 测试文件名称,通常选择需要测试的盘的data目录
-filename=/tmp/fiotest

# 测试绕过机器自带的buffer,是测试结果更真实
-direct=1

# 测试顺序读的I/O
-rw=read

# 测试顺序写的I/O
-rw=write

# 测试顺序混合写和读的I/O
-rw=rw

# 测试随机读的I/O
-rw=randread

# 测试随机写的I/O
-rw=randwrite

# 测试混合随机读和写的I/O
-rw=randrw

# 单次I/O的块文件大小
-bs=4k

# 同上,提定数据块的大小范围
-bsrange=512-2048

# 本次的测试文件大小为5g,以每次4k的io进行测试
-size=5g

# 本次的测试线程为20
-numjobs=20

# 测试时间为60秒,如果不写则一直将5g文件分4k每次写完为止
-runtime=60

# io引擎使用pync方式,如果要使用libaio引擎,需要 yum install libaio-devel包
-ioengine=psync

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

# 关于显示结果的,汇总每个进程的信息
-group_reporting

# 此外
# 只使用1g内存进行测试
-lockmem=1g

# 用0初始化系统buffer
-zero_buffers

# 每个进程生成文件的数量
-nrfiles=8

查看测试结果

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=磁盘利用率

测试吞吐量

yum -y install hdparm

# /dev/sdb1 可修改
hdparm -Tt --direct /dev/sdb1

#参数说明
-t 评估硬盘的读取效率。
-T 评估硬盘快取的读取效率。