linux性能优化磁盘I/O性能优化思路
Posted sysu_lluozh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux性能优化磁盘I/O性能优化思路相关的知识,希望对你有一定的参考价值。
虽然I/O的性能指标很多,相应的性能分析工具也有好几个,但理解了各种指标的含义后就会发现它们其实都有一定的关联
找出了I/O的性能瓶颈后下一步要做的就是优化,也就是如何以最快的速度完成I/O操作,或者换个思路,减少甚至避免磁盘的I/O操作
接下来看看优化I/O性能问题的思路和注意事项
一、I/O基准测试
优化之前先问自己,I/O性能优化的目标是什么?换句话说,观察的这些I/O性能指标(比如 IOPS、吞吐量、延迟等),要达到多少才合适呢?
事实上,I/O性能指标的具体标准每个人估计会有不同的答案,因为每个人的应用场景、使用的文件系统和物理磁盘等,都有可能不一样
为了更客观合理地评估优化效果,首先应该对磁盘和文件系统进行基准测试,得到文件系统或者磁盘I/O的极限性能
fio(Flexible I/O Tester)是最常用的文件系统和磁盘I/O性能基准测试工具
它提供了大量的可定制化选项,可以用来测试裸盘或者文件系统在各种场景下的I/O性能,包括不同块大小、不同I/O引擎以及是否使用缓存等场景
fio的安装比较简单,可以执行下面的命令安装:
# Ubuntu
apt‑get install ‑y fio
# CentOS
yum install ‑y fio
安装完成后,可以执行man fio
查询使用方法
fio的选项非常多,通过几个常见场景的测试方法介绍一些最常用的选项,这些常见场景包括随机读、随机写、顺序读以及顺序写等,执行下面这些命令测试:
# 随机读
fio ‑name=randread ‑direct=1 ‑iodepth=64 ‑rw=randread ‑ioengine=libaio ‑bs=4k ‑size=1G ‑numjobs=1 ‑ru
# 随机写
fio ‑name=randwrite ‑direct=1 ‑iodepth=64 ‑rw=randwrite ‑ioengine=libaio ‑bs=4k ‑size=1G ‑numjobs=1 ‑
# 顺序读
fio ‑name=read ‑direct=1 ‑iodepth=64 ‑rw=read ‑ioengine=libaio ‑bs=4k ‑size=1G ‑numjobs=1 ‑runtime=10
# 顺序写
fio ‑name=write ‑direct=1 ‑iodepth=64 ‑rw=write ‑ioengine=libaio ‑bs=4k ‑size=1G ‑numjobs=1 ‑runtime=
在这其中,有几个参数需要重点关注
- direct
表示是否跳过系统缓存
上面示例中设置的1,表示跳过系统缓存
- iodepth
表示使用异步I/O(asynchronous I/O,简称AIO)时,同时发出的I/O请求上限
在上面的示例中设置的是64
- rw
表示I/O模式
在上面示例中,read/write表示顺序读/写,randread/randwrite表示随机读/写
- ioengine
表示I/O 引擎
支持同步(sync)、异步(libaio)、内存映射(mmap)、网络(net)等各种I/O引擎
在上面示例中,设置的libaio表示使用异步I/O
- bs
表示 I/O 的大小
在上面示例中,设置成了4K(这也是默认值)
- filename
表示文件路径
当然,它可以是磁盘路径(测试磁盘性能),也可以是文件路径(测试文件系统性能)
在上面示例中,把它设置成了磁盘/dev/sdb
不过注意,用磁盘路径测试写会破坏这个磁盘中的文件系统,所以在使用前一定要事先做好数据备份
二、I/O性能优化
得到I/O基准测试报告后,再用上性能分析套路找出I/O的性能瓶颈并优化
当然,想要优化I/O性能肯定离不开Linux系统的I/O栈图的思路辅助
接下来从应用程序、文件系统以及磁盘角度,分别看看I/O性能优化的基本思路
2.1 应用程序优化
首先,来看一下从应用程序的角度有哪些优化I/O的思路
应用程序处于整个I/O栈的最上端,它可以通过系统调用来调整I/O模式(如顺序还是随机、同步还是异步), 同时它也是I/O数据的最终来源
可以有这么几种方式来优化应用程序的I/O性能:
-
第一,可以用追加写代替随机写,减少寻址开销,加快I/O写的速度
-
第二,可以借助缓存I/O,充分利用系统缓存,降低实际I/O的次数
-
第三,可以在应用程序内部构建自己的缓存,或者用Redis这类外部缓存系统
这样,一方面能在应用程序内部控制缓存的数据和生命周期,另一方面也能降低其他应用程序使用缓存对自身的影响 -
第四,在需要频繁读写同一块磁盘空间时,可以用mmap代替read/write,减少内存的拷贝次数
-
第五,在需要同步写的场景中,尽量将写请求合并而不是让每个请求都同步写入磁盘,即可以用
fsync()
取代O_SYNC
-
第六,在多个应用程序共享相同磁盘时,为了保证I/O不被某个应用完全占用,推荐使用cgroups的I/O子系统来限制进程/进程组的IOPS以及吞吐量
-
第七,在使用CFQ调度器时,可以用ionice来调整进程的I/O调度优先级,特别是提高核心应用的 I/O 优先级
ionice支持三个优先级类:Idle、Best-effort和Realtime,其中Best-effort和Realtime还分别支持0-7的级别,数值越小则表示优先级别越高
2.2 文件系统优化
应用程序访问普通文件时,实际是由文件系统间接负责文件在磁盘中的读写,所以跟文件系统中相关的也有很多优化I/O性能的方式
-
第一,可以根据实际负载场景的不同,选择最适合的文件系统
比如Ubuntu默认使用ext4文件系统,而CentOS 7默认使用xfs文件系统 -
第二,在选好文件系统后,可以进一步优化文件系统的配置选项,包括文件系统的特性(如ext_attr、dir_index)、日志模式(如journal、ordered、writeback)、挂载选项(如noatime)等等
-
第三,可以优化文件系统的缓存
比如,可以优化pdflush脏页的刷新频率(比如设置dirty_expire_centisecs和dirty_writeback_centisecs)以及脏页的限额(比如调整dirty_background_ratio和dirty_ratio等)
再如,可以优化内核回收目录项缓存和索引节点缓存的倾向,即调整vfs_cache_pressure(/proc/sys/vm/vfs_cache_pressure,默认值100),数值越大表示越容易回收 -
第四,在不需要持久化时,可以用内存文件系统tmpfs以获得更好的 I/O性能
tmpfs把数据直接保存在内存中而不是磁盘中,比如/dev/shm/就是大多数Linux默认配置的一个内存文件系统,它的大小默认为总内存的一半
2.3 磁盘优化
数据的持久化存储最终还是要落到具体的物理磁盘中,同时,磁盘也是整个I/O栈的最底层。从磁盘角度出发,自然也有很多有效的性能优化方法
-
第一,最简单有效的优化方法,就是换用性能更好的磁盘,比如用SSD替代HDD
-
第二,可以使用 RAID把多块磁盘组合成一个逻辑磁盘,构成冗余独立磁盘阵列。这样做既可以提高数据的可靠性,又可以提升数据的访问性能
-
第三,针对磁盘和应用程序I/O模式的特征,可以选择最适合的I/O调度算法
比方说,SSD和虚拟机中的磁盘通常用的是noop调度算法,而数据库应用推荐使用deadline算法 -
第四,可以对应用程序的数据进行磁盘级别的隔离
比如,可以为日志、数据库等I/O压力比较重的应用,配置单独的磁盘 -
第五,在顺序读比较多的场景中可以增大磁盘的预读数据
比如,可以调整/dev/sdb的预读大小 -
第六,可以优化内核块设备I/O的选项
比如,可以调整磁盘队列的长度/sys/block/sdb/queue/nr_requests适当增大队列长度,可以提升磁盘的吞吐量(当然也会导致I/O延迟增大)
最后,要注意磁盘本身出现硬件错误也会导致I/O性能急剧下降,所以发现磁盘性能急剧下降时,还需要确认磁盘本身是不是出现了硬件错误
比如:
- 可以查看dmesg中是否有硬件I/O故障的日志
- 可以使用badblocks、 smartctl等工具检测磁盘的硬件问题
- 可以用e2fsck等来检测文件系统的错误
如果发现问题可以使用fsck等工具来修复
三、小结
一起梳理了常见的文件系统和磁盘I/O的性能优化思路和方法
发现I/O性能问题后不要急于动手优化,而要先找出最重要的、可以最大程度提升性能的问题,然后再从I/O栈的不同层入手,考虑具体的优化方法
记住,磁盘和文件系统的I/O通常是整个系统中最慢的一个模块。所以,在优化I/O问题时,除了可以优化I/O的执行流程,还可以借助更快的内存、网络、CPU 等减少I/O调用
比如,可以使用这些方式:
- 充分利用系统提供的Buffer、Cache
- 合理使用应用程序内部缓存
- 使用Redis等外部缓存系统
以上是关于linux性能优化磁盘I/O性能优化思路的主要内容,如果未能解决你的问题,请参考以下文章
Linux性能优化实战:Linux 磁盘I/O是怎么工作的(上)(24)