磁盘优化的性能分析工具有不少,往往都有不少的关联性

在找出IO性能的瓶颈之后,下一步就是对其进行优化了,如何以最快的速度完成IO操作,减少IO浪费的时间

对于IO优化的思路,首先你要确定一个IO优化的目标,也就是目标性能指标

那么为了更加合理客观的获取优化效果,我们需要得到文件系统或者磁盘IO的极限性能

fio是常用的文件和磁盘IO性能基准测试工具,提供了大量的可定制化选项,测试文件系统或者磁盘在各种场景下的IO性能,包括不同块大小,不同IO引擎是否使用缓存等场景

fio的安装很简单,使用如下的命令进行获取

yum install -y fio

接下来,我们利用fio来进行测试随机读 随机写 顺序读 顺序写等场景

# 随机读

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

# 随机写

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

# 顺序读

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

# 顺序写

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

在上面的指令中

direct 表示跳过系统缓存,设置的为1 说明跳过系统缓存

iodepth 表示异步io时候, 发出的IO请求上限

rw 表示IO模式,read/write 表示顺序读写 randread/randwrite表示随机读写

ioengine 表示io引擎,支持 sync libaio mmap net 等各种IO引擎

bs,表示IO大小,设置为了4K

filename 可以指定为文件路径,也可以是磁盘路径,磁盘路径的测试写,可能会破坏原本磁盘的文件

fio的测试示例

read: (g=0): rw=read, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=libaio, iodepth=64

fio-3.1

Starting 1 process

Jobs: 1 (f=1): [R(1)][100.0%][r=16.7MiB/s,w=0KiB/s][r=4280,w=0 IOPS][eta 00m:00s]

read: (groupid=0, jobs=1): err= 0: pid=17966: Sun Dec 30 08:31:48 2018

read: IOPS=4257, BW=16.6MiB/s (17.4MB/s)(1024MiB/61568msec)

slat (usec): min=2, max=2566, avg= 4.29, stdev=21.76

clat (usec): min=228, max=407360, avg=15024.30, stdev=20524.39

lat (usec): min=243, max=407363, avg=15029.12, stdev=20524.26

clat percentiles (usec):

|  1.00th=[   498],  5.00th=[  1020], 10.00th=[  1319], 20.00th=[  1713],

| 30.00th=[  1991], 40.00th=[  2212], 50.00th=[  2540], 60.00th=[  2933],

| 70.00th=[  5407], 80.00th=[ 44303], 90.00th=[ 45351], 95.00th=[ 45876],

| 99.00th=[ 46924], 99.50th=[ 46924], 99.90th=[ 48497], 99.95th=[ 49021],

| 99.99th=[404751]

bw (  KiB/s): min= 8208, max=18832, per=99.85%, avg=17005.35, stdev=998.94, samples=123

iops        : min= 2052, max= 4708, avg=4251.30, stdev=249.74, samples=123

lat (usec)   : 250=0.01%, 500=1.03%, 750=1.69%, 1000=2.07%

lat (msec)   : 2=25.64%, 4=37.58%, 10=2.08%, 20=0.02%, 50=29.86%

lat (msec)   : 100=0.01%, 500=0.02%

cpu          : usr=1.02%, sys=2.97%, ctx=33312, majf=0, minf=75

IO depths    : 1=0.1%, 2=0.1%, 4=0.1%, 8=0.1%, 16=0.1%, 32=0.1%, >=64=100.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.1%, >=64=0.0%

issued rwt: total=262144,0,0, short=0,0,0, dropped=0,0,0

latency   : target=0, window=0, percentile=100.00%, depth=64

Run status group 0 (all jobs):

READ: bw=16.6MiB/s (17.4MB/s), 16.6MiB/s-16.6MiB/s (17.4MB/s-17.4MB/s), io=1024MiB (1074MB), run=61568-61568msec

Disk stats (read/write):

sdb: ios=261897/0, merge=0/0, ticks=3912108/0, in_queue=3474336, util=90.09%

在上面中,重点的参数是slat clat lat等几个行

slat是指的从IO提交到实际执行IO的时长

clat IO提交到IO完成的时长

lat 就是fio创建IO到IO完成的总时长

同步IO中,IO提交到实际执行IO是连续的时间,所以slat就是IO完成时间,clat也是0

对于异步IO,lat则等于slat+clat之和

再来看bw,代表吞吐量,吞吐量大约是16MB

平均值为 16MB (17005/1024)

最后的iops,就是每秒IO的次数,平均IOPS是4250个

上面测试的IO大小相同,不能准确的模拟应用程序的IO,所以需要进行配合使用

fio可以进行IO的重放,需要对应的io重放文件,可以利用一个工具类 blktrace

进行IO重放的基准测试,首先是blktrace 记录磁盘设备的IO访问,然后是fio,重放blktrace的记录

基本操作可以如下

blktrace /dev/sdb

ls

sdb.blktrace.0 sdb.blktrace.1

blkparse sdb -d sdb.bin

fio –name=replay –filename=/dev/sdb –direct=1 –read_iolog=sdb.bin

利用这种方式,获取到应用程序IO的基准测试报告

有了性能的实际瓶颈之后,我们就可以进行相关的优化了

我们按照Linux系统整体栈图的思路,进行相关的优化

图片

整体的IO栈图如上

从最上面的应用程序出发

从这个角度,我们可以使用追加写来代替随机写,减少寻址开销,加快IO写的速度

借助缓存IO,充分利用系统缓存,降低实际IO的次数

在应用程序中构建自己的缓存,利用Redis这类外部缓存系统,降低其他应用程序使用缓存对自身的影响

之后,C标准库提供的fopen fread 比 系统直接的 open read 有了标准库的缓存,直接调用只能利用系统提供的页缓存和缓冲区,没有库函数的缓存可以用

fopen提供了用户态的缓存

对于频繁的读写一个磁盘空间的时候,可以使用mmap来代替read/write,减少内存拷贝次数

内存映射文件

使用同步写的时候,将写请求合并,而不是将每个请求都写入磁盘,可以使用fsync()代替O_SYNC

多个应用程序共享磁盘的时候,为了保证IO不被某个应用完全占用,推荐使用cgroups来限制IOPS和吞吐量

最后在 CFQ调度器中,用ionice来调整进程的IO调度优先级,特别是提高核心应用的优先级,ionice支持三个优先级,Idel Best-effort 和 Realtime,Best-effort和Realtime支持0-7的级别,数值越小,优先级越高

然后往下走

我们就能看到文件系统优化

文件系统中也有不同的优化方式,首先根据负载场景不同,选择适合的文件系统,比如Ubuntu默认使用ext4,CentOS使用xfs系统

两者的不同就是xfs可以支持更大磁盘分区和数量,但xfs无法收缩

选好文件系统之后,进一步的优化文件系统的配置

文件系统的特性(ext_attr,dir_index),日志模式(journal,ordered,writeback),挂在选项(noatime)等

使用tune2fs工具,可以调整文件系统的特性,通过/etc/fstab,或者mount命令行参数,调整文件系统的日志模式和挂载选项或者是/etc/fstab 都可以调整文件系统日志模式或者挂载选项

然后是文件系统的缓存

就是pdflush脏页的刷新频率 dirty_expire_centisecs和dirty_writeback_centisecs ,以及脏页的限额 dirty_background_ratio和dirty_ratio等

然后内核回收目录项缓存和索引节点缓存的倾向 调整vfs_cache_pressure 数值越大,越容易回收

不需要持久化的时候,还可以使用tmpfs,获取更好的IO性能,tmpfs将数据保存在内存中,而不是磁盘,比如dev/shm,就是大多数Linux默认配置的一个内存文件系统,默认大小为总内存的一半

到了磁盘角度,就是实际的物理了

简单点,就是SSD代替HDD

然后使用RAID将多个磁盘组成一个逻辑磁盘,提供冗余的磁盘阵列,增强可靠性

针对磁盘和应用程序IO的特征,选择不同的IO调度算法,比如SSD必选noop调度

然后对于应用程序的数据,比如日志,数据库这种重IO的应用,配置单独磁盘

然后优化内核快的IO选项,比如调整磁盘队列的长度 /sys/block/sdb/queue/nr_requests,增大队列长度,提高磁盘吞吐量,但是也会导致IO延迟增加

今天说的主要是常见的文件系统和磁盘IO的性能优化思路和方法,我们发现IO性能之后,找到重要的问题,然后进行具体的优化

优化的方式也要从上往下,从应用程序到文件系统到最终的物理设备

发表评论

邮箱地址不会被公开。 必填项已用*标注