磁盘I/O性能优化的几个思路( 二 )

这个报告中,需要我们重点关注的是,slat、clat、lat,以及 bw 和 iops 这几行 。
先来看刚刚提到的前三个参数 。事实上,slat、clat、lat 都是指 I/O 延迟(latency) 。不同之处在于:

  • slat,是指从 I/O 提交到实际执行 I/O 的时长(Submission latency);
  • clat,是指从 I/O 提交到 I/O 完成的时长(Completion latency);
  • 而 lat,指的是从 fio 创建 I/O 到 I/O 完成的总时长 。
这里需要注意的是,对同步 I/O 来说,由于 I/O 提交和 I/O 完成是一个动作,所以 slat 实际上就是 I/O 完成的时间,而 clat 是 0 。而从示例可以看到,使用异步 I/O(libaio)时,lat 近似等于 slat + clat 之和 。
再来看 bw,它代表吞吐量 。在我上面的示例中,你可以看到,平均吞吐量大约是 16MB(17005 KiB/1024) 。
最后的 iops,其实就是每秒 I/O 的次数,上面示例中的平均 IOPS 为 4250 。
通常情况下,应用程序的 I/O 都是读写并行的,而且每次的 I/O 大小也不一定相同 。所以,刚刚说的这几种场景,并不能精确模拟应用程序的 I/O 模式 。那怎么才能精确模拟应用程序的 I/O 模式呢?
幸运的是,fio 支持 I/O 的重放 。借助前面提到过的 blktrace,再配合上 fio,就可以实现对应用程序 I/O 模式的基准测试 。你需要先用 blktrace,记录磁盘设备的 I/O 访问情况;然后使用 fio,重放 blktrace 的记录 。
比如你可以运行下面的命令来操作:
#使用blktrace跟踪磁盘I/O,注意指定应用程序正在操作的磁盘$ blktrace /dev/sdb#查看blktrace记录的结果# lssdb.blktrace.0sdb.blktrace.1#将结果转化为二进制文件$ blkparse sdb -d sdb.bin#使用fio重放日志$ fio --name=replay --filename=/dev/sdb --direct=1 --read_iolog=sdb.bin这样,我们就通过 blktrace+fio 的组合使用,得到了应用程序 I/O 模式的基准测试报告 。
I/O性能优化得到 I/O 基准测试报告后,再用上我们上一节总结的性能分析套路,找出 I/O 的性能瓶颈并优化,就是水到渠成的事情了 。当然,想要优化 I/O 性能,肯定离不开 linux 系统的I/O 栈图的思路辅助 。你可以结合下面的 I/O 栈图再回顾一下 。
磁盘I/O性能优化的几个思路

文章插图
 
下面,我就带你从应用程序、文件系统以及磁盘角度,分别看看 I/O 性能优化的基本思路 。
应用程序优化首先,我们来看一下,从应用程序的角度有哪些优化 I/O 的思路 。
应用程序处于整个 I/O 栈的最上端,它可以通过系统调用,来调整 I/O 模式(如顺序还是随机、同步还是异步),同时,它也是 I/O 数据的最终来源 。在我看来,可以有这么几种方式来优化应用程序的 I/O 性能 。
第一,可以用追加写代替随机写,减少寻址开销,加快 I/O 写的速度 。
第二,可以借助缓存 I/O,充分利用系统缓存,降低实际 I/O 的次数 。
第三,可以在应用程序内部构建自己的缓存,或者用 redis 这类外部缓存系统 。这样,一方面,能在应用程序内部,控制缓存的数据和生命周期;另一方面,也能降低其他应用程序使用缓存对自身的影响 。
比如,在前面的 MySQL 案例中,我们已经见识过,只是因为一个干扰应用清理了系统缓存,就会导致 MySQL 查询有数百倍的性能差距(0.1s vs 15s) 。
再如,C 标准库提供的 fopen、fread 等库函数,都会利用标准库的缓存,减少磁盘的操作 。而你直接使用 open、read 等系统调用时,就只能利用操作系统提供的页缓存和缓冲区等,而没有库函数的缓存可用 。
第四,在需要频繁读写同一块磁盘空间时,可以用 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 的级别,数值越小,则表示优先级别越高 。
文件系统优化应用程序访问普通文件时,实际是由文件系统间接负责,文件在磁盘中的读写 。所以,跟文件系统中相关的也有很多优化 I/O 性能的方式 。
第一,你可以根据实际负载场景的不同,选择最适合的文件系统 。比如 Ubuntu 默认使用ext4 文件系统,而 CentOS 7 默认使用 xfs 文件系统 。


推荐阅读