1. 程式人生 > >linux 2.6核心的四種IO排程演算法

linux 2.6核心的四種IO排程演算法

 轉自:http://jackyrong.iteye.com/blog/898938

http://blog.csdn.net/theorytree/article/details/6259104

IO排程器的總體目標是希望讓磁頭能夠總是往一個方向移動,移動到底了再往反方向走,

這恰恰就是現實生活中的電梯模型,所以IO調 度器也被叫做電梯. (elevator)而相應的演算法也就被叫做電梯演算法.

1) NOOP 

特點:
在Linux2.4或更早的版本的排程程式,那時只有這一種I/O排程演算法.
NOOP實現了一個簡單的FIFO佇列,它像電梯的工作主法一樣對I/O請求進行組織,當有一個新的請求到來時,

它將請求合併到最近的請求之後,以此來保證請求同一介質。
NOOP傾向餓死讀而利於寫。NOOP對於快閃記憶體裝置,RAM,嵌入式系統是最好的選擇。

電梯演算法餓死讀請求的解釋:

因為寫請求比讀請求更容易.
寫請求通過檔案系統cache,不需要等一次寫完成,就可以開始下一次寫操作,寫請求通過合併,堆積到I/O佇列中.
讀請求需要等到它前面所有的讀操作完成,才能進行下一次讀操作.在讀操作之間有幾毫秒時間,而寫請求在這之間就到來,餓死了後面的讀請求.

NOOP演算法的全寫為No Operation。

該演算法實現了最最簡單的FIFO佇列,所有IO請求大致按照先來後到的順序進行操作。

“大致”原因是NOOP在FIFO的基礎上還做了相鄰IO請求的合併,並不是完完全全按照先進先出的規則滿足IO請求。

NOOP假定I/O請求由驅動程式或者裝置做了優化或者重排了順序(就像一個智慧控制器完成的工作那樣)。

在有些SAN環境下,這個選擇可能是最好選擇。Noop 對 IO 不那麼操心,對所有的 IO請求都用 FIFO 佇列形式處理,預設認為 IO 不會存在效能問題。

這也使得 CPU 也不用那麼操心。當然,對於複雜一點的應用型別,使用這個排程器,使用者自己就會非常操心。 




2) Deadline scheduler 

特點:
通過時間以及硬碟區域進行分類,這個分類和合並要求類似於noop的排程程式.
Deadline確保了在一個截止時間內服務請求,這個截止時間是可調整的,而預設讀期限短於寫期限.這樣就防止了寫操作因為不能被讀取而餓死的現象.
Deadline對資料庫環境(ORACLE RAC,MYSQL等)是最好的選擇.


DEADLINE在CFQ的基礎上,解決了IO請求餓死的極端情況。

除了CFQ本身具有的IO排序佇列之外,DEADLINE額外分別為讀IO和寫IO提供了FIFO佇列。

讀FIFO佇列的最大等待時間為500ms,寫FIFO佇列的最大等待時間為5s。

FIFO佇列內的IO請求優先順序要比CFQ佇列中的高,而讀FIFO佇列的優先順序又比寫FIFO佇列的優先順序高。

優先順序可以表示如下: FIFO(Read) > FIFO(Write) > CFQ 

deadline 演算法保證對於既定的 IO 請求以最小的延遲時間,從這一點理解,對於 DSS 應用應該會是很適合的。 


3) Anticipatory scheduler 

特點:
本質上與Deadline一樣,但在最後一次讀操作後,要等待6ms,才能繼續進行對其它I/O請求進行排程.
可以從應用程式中預訂一個新的讀請求,改進讀操作的執行,但以一些寫操作為代價.
它會在每個6ms中插入新的I/O操作,而會將一些小寫入流合併成一個大寫入流,用寫入延時換取最大的寫入吞吐量.
AS適合於寫入較多的環境,比如檔案伺服器
AS對資料庫環境表現很差.

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 等則會表現的不錯。

這個演算法也可以簡單理解為面向低速磁碟的,因為那個”猜測”實際上的目的是為了減少磁頭移動時間。 


4)CFQ 

特點:
在最新的核心版本和發行版中,都選擇CFQ做為預設的I/O排程器,對於通用的伺服器也是最好的選擇.
CFQ試圖均勻地分佈對I/O頻寬的訪問,避免程序被餓死並實現較低的延遲,是deadline和as排程器的折中.
CFQ對於多媒體應用(video,audio)和桌面系統是最好的選擇.
CFQ賦予I/O請求一個優先順序,而I/O優先順序請求獨立於程序優先順序,高優先順序的程序的讀寫不能自動地繼承高的I/O優先順序.

工作原理:
CFQ為每個程序/執行緒,單獨建立一個佇列來管理該程序所產生的請求,也就是說每個程序一個佇列,各佇列之間的排程使用時間片來排程,
以此來保證每個程序都能被很好的分配到I/O頻寬.I/O排程器每次執行一個程序的4次請求.

CFQ演算法的全寫為Completely Fair Queuing。該演算法的特點是按照IO請求的地址進行排序,而不是按照先來後到的順序來進行響應。 

在傳統的SAS盤上,磁碟尋道花去絕大多數的IO響應時間。CFQ的出發點是對IO地址進行排序,以儘量少的磁碟旋轉次數來滿足儘可能多的IO請求。

在CFQ演算法下,SAS盤的吞吐量大大提高了。但是相比於NOOP的缺點是,先來的IO請求並不一定能被滿足,可能會出現餓死的情況。 

Completely Fair Queuing (cfq, 完全公平佇列) 在 2.6.18 取代了 Anticipatory scheduler 成為 Linux Kernel 預設的 IO scheduler 。

cfq 對每個程序維護一個 IO 佇列,各個程序發來的 IO 請求會被 cfq 以輪循方式處理。也就是對每一個 IO 請求都是公平的。

這使得 cfq 很適合離散讀的應用(eg: OLTP DB)。我所知道的企業級 Linux 發行版中,SuSE Linux 好像是最先預設用 cfq 的. 

檢視當前系統支援的IO排程演算法
dmesg | grep -i scheduler

檢視和修改IO排程器的演算法非常簡單。

假設我們要對sda進行操作,如下所示: 

cat /sys/block/sda/queue/scheduler 
echo “cfq” > /sys/block/sda/queue/scheduler 
想永久的更改I/O排程方法:
修改核心引導引數,加入elevator=排程程式名
vi /boot/grub/menu.lst
更改到如下內容:
kernel /boot/vmlinuz-2.6.18-8.el5 ro root=LABEL=/ elevator=deadline rhgb quiet

總結: 

Anticipatory I/O scheduler                適用於大多數環境,但不太合適資料庫應用

Deadline I/O scheduler                     通常與Anticipatory相當,但更簡潔小巧,更適合於資料庫應用

CFQ I/O scheduler                            為所有程序分配等量的頻寬,適合於桌面多工及多媒體應用,預設IO排程器

Default I/O scheduler


1 CFQ和DEADLINE考慮的焦點在於滿足零散IO請求上。對於連續的IO請求,比如順序讀,並沒有做優化。

為了滿足隨機IO和順序IO混合的場景,Linux還支援ANTICIPATORY排程演算法。

AS的在DEADLINE的基礎上,為每個讀IO都設定了6ms的等待時間視窗。如果在這6ms內OS收到了相鄰位置的讀IO請求,就可以立即滿足。 


IO排程器演算法的選擇,既取決於硬體特徵,也取決於應用場景。 

在傳統的SAS盤上,CFQ、DEADLINE、ANTICIPATORY都是不錯的選擇;

對於專屬的資料庫伺服器,DEADLINE的吞吐量和響應時間都表現良好。

然而在新興的固態硬碟比如SSD、Fusion IO上,最簡單的NOOP反而可能是最好的演算法,因為其他三個演算法的優化是基於縮短尋道時間的,而固態硬碟沒有所謂的尋道時間且IO響應時間非常短。 


2 對於資料庫應用, Anticipatory Scheduler 的表現是最差的。

Deadline 在 DSS 環境表現比 cfq 更好一點,而 cfq 綜合來看錶現更好一些。

這也難怪 RHEL 4 預設的 IO 排程器設定為 cfq. 而 RHEL 4 比 RHEL 3,整體 IO 改進還是不小的。