本帖最后由 白丁 于 2016-11-27 17:35 编辑
1. Noop IO调度 简化的调度程序,实现一个简单的FIFO队列,不进行排序及预寻址操作,只进行最基本的请求合并,专为随机访问设备而设计,比较适合基于Flash的存储器。 该算法在block目录中的noop-iosched.c中实现。 2. anticipatory IO调度 该调度器推迟IO请求,以期能够对他们进行排序,获得最高的效率,每次处理完读请求后,不是立即返回,而是等待几个微秒。在这段时间内,任何来自邻近区域的请求都被立即执行。超时以后,继续原来的处理。 假设一个系统处于非常繁重的写操作期间,每次提交读请求,I/O调度程序都会迅速处理读请求,所以磁盘首先为读操作进行寻址,执行读操作,然后返回再寻址进行写操作,并且对每个读请求都重复这个过程。这种做法对读请求来说是件好事,但是两次寻址操作(一次对读操作的定位,一次返回来进行写操作定位)却损害了系统全局吞吐量。anticipatory IO调度程序的目标是在保持良好的读响应的同时也能提供良好的全局吞吐量。 anticipatory IO调度程序实现了三个队列,并为每个请求设置了超时时间,这点与deadline I/O调度程序一样,anticipatory IO调度程序最主要的改进是增加了预测启发能力。 如果等待可以减少读请求带来的向后再向前寻址操作,那么完全值得花一些时间来等待更多的请求;如果一个相邻的I/O请求在等待期到来,那么I/O调度程序可以节省两次寻址操作。如果存在越来越多的访问同样区域的读请求到来,那么片刻等待无疑会避免大量的寻址操作。 anticipatory IO调度程序所能带来的优势取决于能够正确预测应用程序和文件系统的行为,这种预测依靠一系列的启发和统计工作。 该调度器于2010年从内核中去掉。 该算法在block目录中的as-iosched.c中实现。 3. Deadline IO调度 该调度器时针对anticipatory IO调度器的缺点进行改善而来,它试图把每次请求的延迟降至最低,该算法重拍了请求的顺序来提高性能。它使用轮询的调度器,提供了最小的读取延迟和尚佳的吞吐量,特别适合读取较多的环境(比如数据库)。 出于减少磁盘寻址时间的考虑,对某个磁盘区域上的繁重操作,无疑会使得磁盘其他位置上的操作请求得不到运行机会,实际上,一个对磁盘同一位置操作的请求流可以造成较远位置的其他请求永远得不到运行机会,这是一种很不公平的饥饿现象。更糟糕的是普通的请求饥饿还会带来写-饥饿-读(writes-starving-reads)这种特殊的问题。写操作通常是在内核有空时才将请求提交给磁盘的,写操作完全和提交它的应用程序异步执行;读操作则恰恰星饭,通常当应用程序提交一个读请求时,应用程序会发生堵塞直到读请求被满足,也就是读操作和提交它的应用程序时同步执行的,所以虽然写反应时间不会给系统响应速度造成很大影响,但是读响应时间对系统响应时间来说却不容忽视。虽然写请求时间对应用程序性能带来的影响不大,但是应用程序却必须等待渡情求完成后才能运行其他程序,所以读操作响应时间对系统的性能非常重要。 因为读请求往往相互依靠,这个问题更严重,比如要读大量的文件,每次都是针对一块很小的缓冲区数据区进行读操作,而应用程序只有将上一个数据区从磁盘中读取并返回之后,才能继续读取下一个数据区。不管是读还是写,二者都需要读取像索引节点这样的元数据。 该调度器对降低读操作响应时间做了大量工作,但也降低了系统吞吐量。从磁盘进一步读取这些块会使I/O操作串行化。所以如果每一次请求都发生饥饿现象,那么对读取文件的应用程序来说,全部延迟加起来会造成过长的等待时间。综上所述,读操作具有同步性,并且彼此之间往往相互依靠,所以读请求响应时间直接影响系统性能,因此在2.6版本内核新引入deadline 调度程序来减少饥饿现象,特别是读请求饥饿现象。 在deadline I/O调度中,每个请求都有一个超时时间。默认情况下,读请求的超时时间是500ms,写请求的超时时间是5s。deadline I/O调度类似linux电梯,也以磁盘物理位置为次序维护请求队列,这个队列成为排序队列。当一个新请求递交给排序队列时,调度程序在执行合并和插入请求时类似linus电梯,但是deadline I/O调度程序同时也会以请求类型为依据将他们插入到额外队列中,读请求按次序被插入到特定的读FIFO队列中,写请求被插入到特定的写FIFO队列中。虽然普通队列以磁盘扇区位序进行排列,但是这些队列是以FIFO形式组织的,接过新队列总是被加入到队列尾部。对于普通操作来说,deadline I/O调度程序请求从排序队列的头部取下,再推入到派发队列中,派发队列然后将请求提交给磁盘驱动,从而保证了最小化的请求寻址。 如果在写FIFO队列头,或者是在读FIFO队列头的请求超时,那么deadline I/O调度程序便从FIFO队列中提取请求进行服务。依靠这种方法,deadline I/O调度程序试图保证不会发生有请求在明显超期的情况下仍不能得到服务的现象。 deadline I/O调度程序并不能严格保证请求的响应时间,但是通常情况下,可以再请求超时或超时前提提交和执行,以防止请求饥饿现象的发生。有雨读请求给定的超时时间要比写请求短许多,所以deadline I/O调度程序也确保了写请求不会因为阻塞读请求而使读请求发生饥饿。这种对读操作的照顾确保了读响应时间尽可能短。
该算法在block目录中的deadline-iosched.c中实现。 4. CFQ IO调度(Complete Fair Queuing) 该调度器为系统内所有任务分配均匀的IO带宽,提供公平的工作环境,在多媒体应用中,能保证音视频及时从磁盘中读取数据。 该调度器将IO请求放入特定的队列中,这种队列是根据引起IO请求的进程组织的。在每个队列中,刚进入的请求与相邻请求合并在一起,并进行插入分类,队列由此按扇区方式分类,这与其他IO调度器队列类似,差异在于每一个提交IO的进程都有自己的队列。 该调度器以时间片轮转调度队列,从每个队列中选取请求数(默认值为4,可进行配置),然后进行下一轮调度。这就在进程级提供了公平,确保每个进程接收公平的磁盘带宽片断。 该调度器为系统默认调度器。虽然该调度器主要推荐给桌面工作负荷使用,但它在几乎所有的工作负荷中都能很好的工作。 该算法在block目录的cfq-iosche.c中实现。 5. LINUS电梯 LINUS电梯是在2.4内核中使用的调度器,它能够进行合并与排序预处理。当有新的请求加入队列时,它首先会检查其他每一个挂起的请求是否可以和新请求合并。如果新请求正好连载一个现在的请求前,就是向前合并;如果新请求直接连在一个现存的请求后,就是向后合并,鉴于文件的分布特点和IO曹组执行方式具有典型性(一般都是从头读到尾,很少从反方向读),所以向前合并相比向后合并要少得多,但是linus电梯还是会对两种合并类型进行检查。 当一个请求加入到队列中时,有可能发生四种操作: 1) 如果队列中已存在一个对相邻磁盘扇区操作的请求,那么新请求将和这个已经存在的请求合并成一个请求 2) 如果队列中存在一个驻留时间过长的请求,那么新请求将被插入到队列尾部,以防止其他旧的请求饥饿发生 3) 如果队列中以扇区方向为序存在合适的插入位置,那么新的请求将被插入到该位置,保证队列中的请求是以被访问磁盘物理位置为序进行排列的 4) 如果队列中不存在合适的请求插入位置,请求将被插入到队列尾部
可以通过添加内核启动参数,选择使用的IO调度算法,如:kernel elevator=deadline 给定elevator参数还可以是as、cfq、noop
也可以通过命令改变一个设备的调度器:echo SCHEDULER > /sys/block/DEVICE/queue/scheduler
|