一文帶你走進(jìn)Linux I/O調(diào)度算法
IO調(diào)度器的總體目標(biāo)是希望讓磁頭能夠總是往一個(gè)方向移動(dòng),移動(dòng)到底了再往反方向走,這恰恰就是現(xiàn)實(shí)生活中的電梯模型,所以IO調(diào)度器也被叫做電梯. (elevator)而相應(yīng)的算法也就被叫做電梯算法.而Linux中IO調(diào)度的電梯算法有好幾種,一個(gè)叫做as(Anticipatory),一個(gè)叫做 cfq(Complete Fairness Queueing),一個(gè)叫做deadline,還有一個(gè)叫做noop(No Operation).具體使用哪種算法我們可以在啟動(dòng)的時(shí)候通過內(nèi)核參數(shù)elevator來指定.
一、I/O調(diào)度的4種算法
1)CFQ(完全公平排隊(duì)I/O調(diào)度程序)
特點(diǎn):
在最新的內(nèi)核版本和發(fā)行版中,都選擇CFQ做為默認(rèn)的I/O調(diào)度器,對(duì)于通用的服務(wù)器也是最好的選擇.
CFQ試圖均勻地分布對(duì)I/O帶寬的訪問,避免進(jìn)程被餓死并實(shí)現(xiàn)較低的延遲,是deadline和as調(diào)度器的折中.
CFQ對(duì)于多媒體應(yīng)用(video,audio)和桌面系統(tǒng)是最好的選擇.
CFQ賦予I/O請(qǐng)求一個(gè)優(yōu)先級(jí),而I/O優(yōu)先級(jí)請(qǐng)求獨(dú)立于進(jìn)程優(yōu)先級(jí),高優(yōu)先級(jí)的進(jìn)程的讀寫不能自動(dòng)地繼承高的I/O優(yōu)先級(jí).
工作原理:
CFQ為每個(gè)進(jìn)程/線程,單獨(dú)創(chuàng)建一個(gè)隊(duì)列來管理該進(jìn)程所產(chǎn)生的請(qǐng)求,也就是說每個(gè)進(jìn)程一個(gè)隊(duì)列,各隊(duì)列之間的調(diào)度使用時(shí)間片來調(diào)度,
以此來保證每個(gè)進(jìn)程都能被很好的分配到I/O帶寬.I/O調(diào)度器每次執(zhí)行一個(gè)進(jìn)程的4次請(qǐng)求.
2)NOOP(電梯式調(diào)度程序)
特點(diǎn):
在Linux2.4或更早的版本的調(diào)度程序,那時(shí)只有這一種I/O調(diào)度算法.
NOOP實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的FIFO隊(duì)列,它像電梯的工作主法一樣對(duì)I/O請(qǐng)求進(jìn)行組織,當(dāng)有一個(gè)新的請(qǐng)求到來時(shí),它將請(qǐng)求合并到最近的請(qǐng)求之后,以此來保證請(qǐng)求同一介質(zhì).
NOOP傾向餓死讀而利于寫.
NOOP對(duì)于閃存設(shè)備,RAM,嵌入式系統(tǒng)是最好的選擇.
電梯算法餓死讀請(qǐng)求的解釋:
因?yàn)閷懻?qǐng)求比讀請(qǐng)求更容易.
寫請(qǐng)求通過文件系統(tǒng)cache,不需要等一次寫完成,就可以開始下一次寫操作,寫請(qǐng)求通過合并,堆積到I/O隊(duì)列中.
讀請(qǐng)求需要等到它前面所有的讀操作完成,才能進(jìn)行下一次讀操作.在讀操作之間有幾毫秒時(shí)間,而寫請(qǐng)求在這之間就到來,餓死了后面的讀請(qǐng)求.
3)Deadline(截止時(shí)間調(diào)度程序)
特點(diǎn):
通過時(shí)間以及硬盤區(qū)域進(jìn)行分類,這個(gè)分類和合并要求類似于noop的調(diào)度程序.
Deadline確保了在一個(gè)截止時(shí)間內(nèi)服務(wù)請(qǐng)求,這個(gè)截止時(shí)間是可調(diào)整的,而默認(rèn)讀期限短于寫期限.這樣就防止了寫操作因?yàn)椴荒鼙蛔x取而餓死的現(xiàn)象.
Deadline對(duì)數(shù)據(jù)庫(kù)環(huán)境(ORACLE RAC,MYSQL等)是最好的選擇.
4)AS(預(yù)料I/O調(diào)度程序)
特點(diǎn):
本質(zhì)上與Deadline一樣,但在最后一次讀操作后,要等待6ms,才能繼續(xù)進(jìn)行對(duì)其它I/O請(qǐng)求進(jìn)行調(diào)度.
可以從應(yīng)用程序中預(yù)訂一個(gè)新的讀請(qǐng)求,改進(jìn)讀操作的執(zhí)行,但以一些寫操作為代價(jià).
它會(huì)在每個(gè)6ms中插入新的I/O操作,而會(huì)將一些小寫入流合并成一個(gè)大寫入流,用寫入延時(shí)換取最大的寫入吞吐量.
AS適合于寫入較多的環(huán)境,比如文件服務(wù)器
AS對(duì)數(shù)據(jù)庫(kù)環(huán)境表現(xiàn)很差.
【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【891587639】整理了一些個(gè)人覺得比較好的學(xué)習(xí)書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦?。。。ê曨l教程、電子書、實(shí)戰(zhàn)項(xiàng)目及代碼)? ??


二、查看系統(tǒng)配置
1.查看當(dāng)前系統(tǒng)支持的IO調(diào)度算法
dmesg | grep -i scheduler
[root@localhost ~]# dmesg | grep -i scheduler
io scheduler noop registered
io scheduler anticipatory registered
io scheduler deadline registered
io scheduler cfq registered (default)
2.查看當(dāng)前系統(tǒng)的I/O調(diào)度方法:
cat /sys/block/sda/queue/scheduler
noop anticipatory deadline [cfq]
臨地更改I/O調(diào)度方法:
例如:想更改到noop電梯調(diào)度算法:
echo noop > /sys/block/sda/queue/scheduler
3.永久的更改I/O調(diào)度方法:
修改內(nèi)核引導(dǎo)參數(shù),加入elevator=調(diào)度程序名
vi /boot/grub/menu.lst
更改到如下內(nèi)容:
kernel /boot/vmlinuz-2.6.18-8.el5 ro root=LABEL=/ elevator=deadline rhgb quiet
重啟之后,查看調(diào)度方法:
cat /sys/block/sda/queue/scheduler
noop anticipatory [deadline] cfq
已經(jīng)是deadline了
三、I/O調(diào)度程序的測(cè)試
本次測(cè)試分為只讀,只寫,讀寫同時(shí)進(jìn)行.
分別對(duì)單個(gè)文件600MB,每次讀寫2M,共讀寫300次.
1.測(cè)試磁盤讀:
[root@test1 tmp]# echo deadline > /sys/block/sda/queue/scheduler
[root@test1 tmp]# time dd if=/dev/sda1 f=/dev/null bs=2M count=300
300+0 records in
300+0 records out
629145600 bytes (629 MB) copied, 6.81189 seconds, 92.4 MB/s
real 0m6.833s
user 0m0.001s
sys 0m4.556s
[root@test1 tmp]# echo noop > /sys/block/sda/queue/scheduler
[root@test1 tmp]# time dd if=/dev/sda1 f=/dev/null bs=2M count=300
300+0 records in
300+0 records out
629145600 bytes (629 MB) copied, 6.61902 seconds, 95.1 MB/s
real 0m6.645s
user 0m0.002s
sys 0m4.540s
[root@test1 tmp]# echo anticipatory > /sys/block/sda/queue/scheduler
[root@test1 tmp]# time dd if=/dev/sda1 f=/dev/null bs=2M count=300
300+0 records in
300+0 records out
629145600 bytes (629 MB) copied, 8.00389 seconds, 78.6 MB/s
real 0m8.021s
user 0m0.002s
sys 0m4.586s
[root@test1 tmp]# echo cfq > /sys/block/sda/queue/scheduler
[root@test1 tmp]# time dd if=/dev/sda1 f=/dev/null bs=2M count=300
300+0 records in
300+0 records out
629145600 bytes (629 MB) copied, 29.8 seconds, 21.1 MB/s
real 0m29.826s
user 0m0.002s
sys 0m28.606s
結(jié)果:
第一 noop:用了6.61902秒,速度為95.1MB/s
第二 deadline:用了6.81189秒,速度為92.4MB/s
第三 anticipatory:用了8.00389秒,速度為78.6MB/s
第四 cfq:用了29.8秒,速度為21.1MB/s
2.測(cè)試寫磁盤:
[root@test1 tmp]# echo cfq > /sys/block/sda/queue/scheduler
[root@test1 tmp]# time dd if=/dev/zero f=/tmp/test bs=2M count=300
300+0 records in
300+0 records out
629145600 bytes (629 MB) copied, 6.93058 seconds, 90.8 MB/s
real 0m7.002s
user 0m0.001s
sys 0m3.525s
[root@test1 tmp]# echo anticipatory > /sys/block/sda/queue/scheduler
[root@test1 tmp]# time dd if=/dev/zero f=/tmp/test bs=2M count=300
300+0 records in
300+0 records out
629145600 bytes (629 MB) copied, 6.79441 seconds, 92.6 MB/s
real 0m6.964s
user 0m0.003s
sys 0m3.489s
[root@test1 tmp]# echo noop > /sys/block/sda/queue/scheduler
[root@test1 tmp]# time dd if=/dev/zero f=/tmp/test bs=2M count=300
300+0 records in
300+0 records out
629145600 bytes (629 MB) copied, 9.49418 seconds, 66.3 MB/s
real 0m9.855s
user 0m0.002s
sys 0m4.075s
[root@test1 tmp]# echo deadline > /sys/block/sda/queue/scheduler
[root@test1 tmp]# time dd if=/dev/zero f=/tmp/test bs=2M count=300
300+0 records in
300+0 records out
629145600 bytes (629 MB) copied, 6.84128 seconds, 92.0 MB/s
real 0m6.937s
user 0m0.002s
sys 0m3.447s
測(cè)試結(jié)果:
第一 anticipatory,用了6.79441秒,速度為92.6MB/s
第二 deadline,用了6.84128秒,速度為92.0MB/s
第三 cfq,用了6.93058秒,速度為90.8MB/s
第四 noop,用了9.49418秒,速度為66.3MB/s
3.測(cè)試同時(shí)讀/寫
[root@test1 tmp]# echo deadline > /sys/block/sda/queue/scheduler
[root@test1 tmp]# dd if=/dev/sda1 f=/tmp/test bs=2M count=300
300+0 records in
300+0 records out
629145600 bytes (629 MB) copied, 15.1331 seconds, 41.6 MB/s
[root@test1 tmp]# echo cfq > /sys/block/sda/queue/scheduler
[root@test1 tmp]# dd if=/dev/sda1 f=/tmp/test bs=2M count=300
300+0 records in
300+0 records out
629145600 bytes (629 MB) copied, 36.9544 seconds, 17.0 MB/s
[root@test1 tmp]# echo anticipatory > /sys/block/sda/queue/scheduler
[root@test1 tmp]# dd if=/dev/sda1 f=/tmp/test bs=2M count=300
300+0 records in
300+0 records out
629145600 bytes (629 MB) copied, 23.3617 seconds, 26.9 MB/s
[root@test1 tmp]# echo noop > /sys/block/sda/queue/scheduler
[root@test1 tmp]# dd if=/dev/sda1 f=/tmp/test bs=2M count=300
300+0 records in
300+0 records out
629145600 bytes (629 MB) copied, 17.508 seconds, 35.9 MB/s
測(cè)試結(jié)果:
第一 deadline,用了15.1331秒,速度為41.6MB/s
第二 noop,用了17.508秒,速度為35.9MB/s
第三 anticipatory,用了23.3617秒,速度為26.9MS/s
第四 cfq,用了36.9544秒,速度為17.0MB/s
四、ionice更改任務(wù)的類型和優(yōu)先級(jí)
ionice可以更改任務(wù)的類型和優(yōu)先級(jí),不過只有cfq調(diào)度程序可以用ionice.
有三個(gè)例子說明ionice的功能:
采用cfq的實(shí)時(shí)調(diào)度,優(yōu)先級(jí)為7
ionice -c1 -n7 -ptime dd if=/dev/sda1 f=/tmp/test bs=2M count=300&
采用缺省的磁盤I/O調(diào)度,優(yōu)先級(jí)為3
ionice -c2 -n3 -ptime dd if=/dev/sda1 f=/tmp/test bs=2M count=300&
采用空閑的磁盤調(diào)度,優(yōu)先級(jí)為0
ionice -c3 -n0 -ptime dd if=/dev/sda1 f=/tmp/test bs=2M count=300&
ionice的三種調(diào)度方法,實(shí)時(shí)調(diào)度最高,其次是缺省的I/O調(diào)度,最后是空閑的磁盤調(diào)度.
ionice的磁盤調(diào)度優(yōu)先級(jí)有8種,最高是0,最低是7.
注意,磁盤調(diào)度的優(yōu)先級(jí)與進(jìn)程nice的優(yōu)先級(jí)沒有關(guān)系.
一個(gè)是針對(duì)進(jìn)程I/O的優(yōu)先級(jí),一個(gè)是針對(duì)進(jìn)程CPU的優(yōu)先級(jí).
Anticipatory I/O scheduler 適用于大多數(shù)環(huán)境,但不太合適數(shù)據(jù)庫(kù)應(yīng)用
Deadline I/O scheduler 通常與Anticipatory相當(dāng),但更簡(jiǎn)潔小巧,更適合于數(shù)據(jù)庫(kù)應(yīng)用
CFQ I/O scheduler 為所有進(jìn)程分配等量的帶寬,適合于桌面多任務(wù)及多媒體應(yīng)用,默認(rèn)IO調(diào)度器
Default I/O scheduler
