IO调度器设计考虑

 

通过前面的分析已经知道IO调度器主要是为了解决临近IO合并的问题。磁介质存储盘最大的性能瓶颈在于寻道。当用户访问一个指定地址时,磁盘首先需要进行寻道操作,找到访问地址所属的区域。这种操作往往是毫秒级别的,相对于性能不断提升的CPU而言,这种性能显然是不可接受的。所以,磁盘最大的问题在于机械操作引入的寻道时间过长,对外表现就是随机读写性能太差了。

 

为了弥补这种性能弱点,Linux操作系统系统在设计的时候引入了IO调度器,尽最大可能将随机读写转换成大块顺序读写,减少磁盘抖动,降低若干IO操作之间的寻道时间。IO调度器的目的就在于此,它的初衷是面向存储介质设计的。因此,当一个系统的存储介质发生变化之后,IO调度器就需要改变。例如,针对SSD存储介质,传统意义上的IO调度算法就不再适用了。SSD不存在机械操作,不存在漫长的寻道时间问题,因此,不存在传统磁介质的随机读写问题。但是,SSD存在写放大的问题,一个小写会引入大量的数据读写操作,从而使得IO性能下降。所以,传统磁盘的IO调度器在SSD面前就没有价值了,可以采用最简单的Noop调度器对IO进行后向合并就可以了,而写放大等问题往往都在SSD内部的Firmware解决了。

 

考虑一下,如果设计的IO调度器完全面向存储介质,那么设计的调度算法只需要考虑IO请求的前向/后向合并就可以了,这样的IO合并减少了磁头的抖动,就像一部电梯一样,一直往一个方向移动。这种算法看上去很完美,但是,在实践中我们会发现有些请求会长时间得不到服务,就像一辆电梯厂时间停在一个楼层,其他楼层的人长时间得不到服务。特别对于一些读操作,往往是同步请求,如果长时间得不到服务,那么会大大影响应用的性能。所以,仅仅简单的考虑存储介质的特性,进行IO的前向/后向合并是不够的,还需要考虑IO的本身属性。

 

IO的属性来看,最需要区分的是读写请求,读写请求的优先级是不一样的,大多数写请求可以异步完成,读请求需要同步完成,所以,对于读写请求可以分开处理。虽然分开之后可能会引入更多的磁盘抖动,但是,应用的整体性能还是会提高。

 

考虑了IO的基本属性之外,是不是就够了呢?其实还是不够的。例如在一个服务器中存在多个应用,这些应用会访问相同的存储,有些应用读请求多,有些应用写请求多,如果仅仅考虑IO的基本属性,那么对于这些不同的应用就会表现出不同的IO性能。有些应用得到较多的IO带宽,性能较好;有些应用得到较少的带宽,性能较差。这显然是不合理的,由于调度算法的策略问题,导致一个系统中,不同应用具有不同的IO性能。为了解决这个问题,需要考虑应用属性。

 

在现有的Linux系统中,提供了多种IO调度器,这些调度器有些仅仅考虑了存储介质属性(Noop),有些考虑了IO属性(Deadline),还有的考虑了应用属性(cfq)。不同调度器的设计考虑范畴不同,所以复杂度也有很大差别。下面会对Linux中的这几种调度器进行阐述。

 

<待续。。。>