Linux性能学习第四周-IO性能优化

2166 words, 7 mins

linux 性能优化学习第四周总结,本周主要是 IO性能优化

记得以前在优化交易所撮合引擎的时候,发现瓶颈都在 mysql ,而正如倪老师所说,数据库一般都看 iops,确实当时的优化主要就是提升硬盘的 iops,也就是直接用更好的硬盘。这也是最简单有效,直接烧钱的方案。刚开始我们的硬盘是 3000 iops,撮合引擎能做到 3000 tps,后来增加硬盘到 6000 iops,tps 能到6000+,大概是这样的数据。

至于后面做到 10000+的 tps,就不是靠堆硬件了,还是需要优化架构,让整个撮合到结算的流程都放在内存中执行,落库用异步任务批量处理,再加上使用了Event sourcing 的概念,保存数据大多数也只是insert,相比以前一堆的transaction,包裹一堆的insert, update,甚至还需要lock住相关数据,新的方案甚至可以很轻松的切换数据库,简直不要太厉害(哈哈)。

学完本周课程,比起以前只会简单看下 iops 的数据,现在有了更多的观察角度和维度,感觉以后面对研发遇到的性能瓶颈,会更加有信心去优化。

读写文件也是有内存缓存的

Linux 系统为每个文件都分配了两个数据结构:索引节点(index node)和目录项(directory entry)

操作系统为了协调慢速磁盘与快速 CPU 的性能差异,文件内容会缓存到页缓存Cache 中,索引节点也会缓存到内存中,加速文件访问。

顺序读的性能要优于随机读

不管是机械磁盘(Hard Disk Driver)还是固态硬盘(Solid State Disk),顺序读的性能都要优于随机读

如何快速定位IO 瓶颈?

首先,我们需要知道我们的设备能撑到什么程度,就比如 iops 最大能到多少,读写可以每秒多大数据.

然后就可以开始查看磁盘 io 信息

img

借助上图,分析步骤可以为:

  • 先用 iostat 发现磁盘 I/O 性能瓶颈;
  • 再借助 pidstat ,定位出导致瓶颈的进程;
  • 随后分析进程的 I/O 行为;
  • 最后,结合应用程序的原理,分析这些 I/O 的来源。

img

结合 IO 栈图

应用程序优化步骤:

  • 第一,可以用追加写代替随机写,减少寻址开销,加快 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 的级别,数值越小,则表示优先级别越高。

文件系统优化:

  • 第一,你可以根据实际负载场景的不同,选择最适合的文件系统。比如 Ubuntu 默认使用 ext4 文件系统,而 CentOS 7 默认使用 xfs 文件系统。
  • 第二,在选好文件系统后,还可以进一步优化文件系统的配置选项,包括文件系统的特性(如 ext_attr、dir_index)、日志模式(如 journal、ordered、writeback)、挂载选项(如 noatime)等等。
  • 第三,可以优化文件系统的缓存。
  • 最后,在不需要持久化时,你还可以用内存文件系统 tmpfs,以获得更好的 I/O 性能 。tmpfs 把数据直接保存在内存中,而不是磁盘中。比如 /dev/shm/ ,就是大多数 Linux 默认配置的一个内存文件系统,它的大小默认为总内存的一半。

磁盘优化:

  • 第一,最简单有效的优化方法,就是换用性能更好的磁盘,比如用 SSD 替代 HDD。
  • 第二,我们可以使用 RAID ,把多块磁盘组合成一个逻辑磁盘,构成冗余独立磁盘阵列。这样做既可以提高数据的可靠性,又可以提升数据的访问性能。
  • 第三,针对磁盘和应用程序 I/O 模式的特征,我们可以选择最适合的 I/O 调度算法。比方说,SSD 和虚拟机中的磁盘,通常用的是 noop 调度算法。而数据库应用,我更推荐使用 deadline 算法。
  • 第四,我们可以对应用程序的数据,进行磁盘级别的隔离。比如,我们可以为日志、数据库等 I/O 压力比较重的应用,配置单独的磁盘。
  • 第五,在顺序读比较多的场景中,我们可以增大磁盘的预读数据。
  • 第六,我们可以优化内核块设备 I/O 的选项。比如,可以调整磁盘队列的长度 /sys/block/sdb/queue/nr_requests,适当增大队列长度,可以提升磁盘的吞吐量(当然也会导致 I/O 延迟增大)。
  • 最后,要注意,磁盘本身出现硬件错误,也会导致 I/O 性能急剧下降,所以发现磁盘性能急剧下降时,你还需要确认,磁盘本身是不是出现了硬件错误。

推荐书籍

windows: 《Windows Internals 7th edition》

linux: 《深入Linux内核架构》