Contents

一. IO调度器(IO Scheduler)是操作系统用来决定块设备上IO操作提交顺序的方法。存在的目的有两个,一是提高IO吞吐量,二是降低IO响应时间。然而IO吞吐量和IO响应时间往往是矛盾的,为了尽量平衡这两者,IO调度器提供了多种调度算法来适应不同的IO请求场景。其中,对数据库这种随机读写的场景最有利的算法是DEADLINE。接着我们按照从简单到复杂的顺序,下面是Linux 2.6内核提供的几种IO调度算法。

1、NOOP
NOOP算法的全写为No Operation。该算法实现了最最简单的FIFO队列(First Input First Output的缩写,先进先出队列,这是一种传统的按序执行方法,先进入的指令先完成并引退,跟着才执行第二条指令),所有IO请求大致按照先来后到的顺序进行操作。之所以说“大致”,原因是NOOP在FIFO的基础上还做了相邻IO请求的合并,并不是完完全全按照先进先出的规则满足IO请求。
假设有如下的io请求序列:
100,500,101,10,56,1000
NOOP将会按照如下顺序满足:
100(101),500,10,56,1000

2、CFQ
CFQ算法的全写为Completely Fair Queuing。该算法的特点是按照IO请求的地址进行排序,而不是按照先来后到的顺序来进行响应。
假设有如下的io请求序列:
100,500,101,10,56,1000
CFQ将会按照如下顺序满足:
100,101,500,1000,10,56

在传统的SAS盘上,磁盘寻道花去了绝大多数的IO响应时间。CFQ的出发点是对IO地址进行排序,以尽量少的磁盘旋转次数来满足尽可能多的IO请求。在CFQ算法下,SAS盘的吞吐量大大提高了。但是相比于NOOP的缺点是,先来的IO请求并不一定能被满足,可能会出现饿死的情况。

3、DEADLINE
DEADLINE在CFQ的基础上,解决了IO请求饿死的极端情况。除了CFQ本身具有的IO排序队列之外,DEADLINE额外分别为读IO和写IO提供了FIFO队列。读FIFO队列的最大等待时间为500ms,写FIFO队列的最大等待时间为5s。FIFO队列内的IO请求优先级要比CFQ队列中的高,,而读FIFO队列的优先级又比写FIFO队列的优先级高。优先级可以表示如下:
FIFO(Read) > FIFO(Write) > CFQ

DEADLINE调度算法主要针对I/O请求的延时而设计,每个I/O请求都被附加一个最后执行期限。如果发现过期的I/O请求,则会处理按照过期时间排序的队列,直到所有过期请求都被发射为止。在处理请求时,该算法会优先考虑读请求。该算法维护两类队列,一是按照扇区排序的读写请求队列;二是按照过期时间排序的读写请求队列。如果当前没有I/O请求过期,则会按照扇区顺序执行I/O请求;

当系统中存在的I/O请求进程数量比较少时,与CFQ算法相比,DEADLINE算法可以提供较高的I/O吞吐率。

DEADLINE调度算法提供如下参数

[root@guo ~ ] #ls /sys/block/sda/queue/iosched/

fifo_batch front_merges read_expire write_expire writes_starved

writes_starved:该参数控制当读写队列均不为空时,发射多少个读请求后,允许发射写请求。

read_expire:参数控制读请求的过期时间,单位毫秒。

write_expire:参数控制写请求的过期时间,单位毫秒。 

4、ANTICIPATORY

CFQ和DEADLINE考虑的焦点在于满足零散IO请求上。对于连续的IO请求,比如顺序读,并没有做优化。为了满足随机IO和顺序IO混合的场景,Linux还支持ANTICIPATORY调度算法。ANTICIPATORY在DEADLINE的基础上,为每个读IO都设置了6ms的等待时间窗口。如果在这6ms内OS收到了相邻位置的读IO请求,就可以立即满足Anticipatory scheduler(as) 曾经一度是 Linux 2.6 Kernel 的 IO scheduler 。Anticipatory 的中文含义是”预料的, 预想的”, 这个词的确揭示了这个算法的特点,简单的说,有个 IO 发生的时候,如果又有进程请求 IO 操作,则将产生一个默认的 6 毫秒猜测时间,猜测下一个进程请求 IO 是要干什么的。这对于随即读取会造成比较大的延时,对数据库应用很糟糕,而对于 Web Server 等则会表现的不错。
这个算法也可以简单理解为面向低速磁盘的,因为那个”猜测”实际上的目的是为了减少磁头移动时间。

二. Linux操作系统IO调度器算法的查看和修改(以CentOS6.3为例):

[mysql@guo ~]$ cat /etc/redhat-release 
CentOS release 6.3 (Final)

[mysql@guo ~]$ uname -a
Linux mysql 2.6.32-279.el6.x86_64 #1 SMP Fri Jun 22 12:19:21 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux
[mysql@guo ~]$ 

1.机器为2.6内核,查看IO调度算法设置的方法:

[root@guo ~]# fdisk -l

Disk /dev/sda: 126.7 GB, 126701535232 bytes
255 heads, 63 sectors/track, 15403 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00016b9b

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *           1          26      204800   83  Linux
Partition 1 does not end on cylinder boundary.
/dev/sda2              26         217     1536000   82  Linux swap / Solaris
Partition 2 does not end on cylinder boundary.
/dev/sda3             217       15404   121990144   8e  Linux LVM

Disk /dev/mapper/vg_guo-LogVol00: 62.9 GB, 62914560000 bytes
255 heads, 63 sectors/track, 7648 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000


Disk /dev/mapper/vg_guo-LogVol01: 62.0 GB, 62000201728 bytes
255 heads, 63 sectors/track, 7537 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000


[root@guo ~]# find / -iname "scheduler"

/sys/block/sr0/queue/scheduler

/sys/block/sda/queue/scheduler

查看系统当前IO调度算法

[root@guo ~]# cat /sys/block/sda/queue/scheduler

noop anticipatory deadline [cfq]    ----括号中为当前使用的算法

2.修改IO调度算法:

[root@guo ~]# echo deadline > /sys/block/sda/queue/scheduler

[root@guo ~]# cat /sys/block/sda/queue/scheduler

noop anticipatory [deadline] cfq  可以看到IO调度算法已经修改为deadline
重启失效,会还原成默认cfq

想永久的更改I/O调度方法:

修改内核引导参数,加入elevator=调度程序名
vi /boot/grub/menu.lst

更改到如下内容:

kernel /vmlinuz-2.6.32-279.el6.x86_64 ro root=/dev/mapper/vg_guo-LogVol00  elevator=deadline rhgb quiet

三. 针对MYSQL数据库服务器的IO调度算法优化设置:

1.CFQ使用于IO大小非常均匀的场景

2.比较复杂的OLTP环境最好使用DeadLine算法

3.IO性能不是瓶颈的时候可以使用Noop算法

4.Anticipatory不适合数据库环境,DB服务器不要使用这种算法。

5.新兴的固态硬盘比如SSD、Fusion IO上,最简单的NOOP反而可能是最好的算法,因为其他三个算法的优化是基于缩短寻道时间的,而固态硬盘没有所谓的寻道时间且IO响应时间非常短。

Contents