Linux IO調度(電梯算法) 磁盤IO的基礎原理 Linux IO調度(電梯算法) IO調度配置 總結 參考文章

磁盤IO的基礎原理

磁盤的組成

一塊機械硬盤是由盤面、磁頭和懸臂三個部件組成的。

  1. 盤面:是實際存儲數據的盤片。盤面上有一層磁性的塗層。數據就存儲在這個磁性的塗層上。 盤面中間有一個受電機控制的轉軸。這個轉軸會控制盤面去旋轉。與盤面有關係的指標叫轉速,如硬盤有5400 轉的、7200 轉的,乃至 10000 轉的。這個多少多少轉,指的就是盤面中間電機控制的轉軸的旋轉速度,英文單位叫RPM,也就是每分鐘的旋轉圈數。7200RPM,指的就是一旦電腦開機供電之後,我們的硬盤就可以一直做到每分鐘轉上 7200 圈。如果折算到每一秒鐘,就是 120 圈。

  2. 磁頭:數據並不能直接從盤面傳輸到總線上,而是通過磁頭,從盤面上讀取到,然後再通過電路信號傳輸給控制電路、接口,再到總線上的。通常,一個盤面上會有兩個磁頭,分別在盤面的正反面。盤面在正反兩面都有對應的磁性塗層來存儲數據,而且一塊硬盤也不是隻有一個盤面,而是上下堆疊了很多個盤面,各個盤面之間是平行的。每個盤面的正反兩面都有對應的磁頭。

  3. 懸臂:懸臂鏈接在磁頭上,並且在一定範圍內會去把磁頭定位到盤面的某個特定的磁道上。

一個盤面通常是圓形的,由很多個同心圓組成,每一圈都是一個磁道。每個磁道都有自己的一個編號。懸臂其實只是控制,到底是讀最裏面那個圈的數據,還是最外面圈的數據

一個磁道,會分成一個一個扇區。上下平行的一個一個盤面的相同扇區呢,叫作一個柱面,讀取數據,兩個步驟。

  1. 把盤面旋轉到某一個位置。在這個位置上,懸臂可以定位到整個盤面的某一個子區間。這個子區間的形狀有點兒像一塊披薩餅,一般把這個區間叫作幾何扇區。意思是,在幾何位置上,所有這些扇區都可以被懸臂訪問到。

  2. 就是把懸臂移動到特定磁道的特定扇區,也就在這個幾何扇區裏面,找到我們實際的扇區。找到之後,磁頭會落下,就可以讀取到正對着扇區的數據。

數據存取方式

磁盤的數據讀/寫一般是按柱面進行的,即讀/寫數據時首先在同一柱面內從“0”磁頭開始進行操作,依次向下在同一柱面的不同盤面即不同磁頭上進行操作,只有當同一柱面所有的磁頭全部讀/寫完畢後,磁頭才轉移到下一柱面(即尋道)。

因爲切換磁頭只需通過電子設備切換即可,而切換柱面則必須通過機械設備切換。電子磁頭間的切換比機械磁頭向臨近磁道或柱面切換要快的多。所以,數據的讀/寫按柱面進行,而不按盤面進行。也就是說,一個磁道寫滿數據後,就在同一柱面的下一個盤面的相同半徑磁道來寫,一個柱面寫滿後,才移到下一個柱面開始寫數據。讀數據也按照這種方式進行,這樣就大大提高了磁盤的讀/寫效率。

磁盤數據定位

機械硬盤的硬件,主要由盤面、磁頭和懸臂三部分組成。我們的數據在盤面上的位置,可以通過磁道、扇區和柱面來定位。實際的一次對於硬盤的訪問,需要把盤面旋轉到某一個“幾何扇區”,對準懸臂的位置。然後,懸臂通過尋道,把磁頭放到我們實際要讀取的扇區上。

受制於機械硬盤的結構,我們對於隨機數據的訪問速度,就要包含旋轉盤面的平均延時和移動懸臂的尋道時間。

磁盤尋道示例

數據存放在磁盤的第六磁道的第八扇區上:

那磁頭就會先擺動到第六磁道上空,然後等待第八扇區轉過來。當第八扇區轉到磁頭下面的時候,纔可以讀取數據。

這就是機械硬盤的工作原理,也正是因爲機械硬盤是利用磁性極粒來存儲數據的,所以機械硬盤通常又被稱作磁盤。

磁盤數據尋址方式

訪問硬盤上的數據總是以扇區爲單位進行的,即每次讀或寫至少是一個扇區的數據。
常用兩種:物理尋址方式(CHS)和邏輯尋址方式(LBA)

物理尋址方式

物理尋址方式又稱爲CHS(Cylinder柱面/Head磁頭/Sector扇區)方式,用柱面號(即磁道號)、磁頭號(即盤面號)和扇區號來表示一個特定扇區。柱面和扇區從0開始編號,而扇區從1開始編號的。
磁盤容量=磁頭數×柱面數×扇區數×512字節
系統在寫入數據時是按照從柱面到柱面的方式,當上一個柱面寫滿數據後才移動磁頭到下一個柱面,而且是從柱面的第一個磁頭的第一個扇區開始寫入,從而使磁盤性能最優。

邏輯尋址方式

尋址方式也改爲以扇區爲單位的線性尋址,這種尋址方式便是LBA。即將所有的扇區統一編號。C/H/S中的扇區編號是從“1”至“63”,而邏輯扇區LBA方式下扇區是從“0”開始編號,所有扇區編號按順序進行。
對於任何一個硬盤,都可以認爲其扇區是從0號開始。

硬盤特性

硬盤尋址時間

即完成一個io請求所花費的時間(它由尋道時間、旋轉延遲和數據傳輸時間三部分構成)

  1. 尋道時間:磁頭移動到數據所在磁道的時間

7200 rpm的硬盤平均物理尋道時間是9ms

10000 rpm的硬盤平均物理尋道時間是6ms

15000 rpm的硬盤平均物理尋道時間是4ms

  1. 旋轉延遲時間:磁頭移動到數據所在磁道後,數據轉到磁頭下的時間(旋轉延遲取決於磁盤轉速,通常使用磁盤旋轉一週所需時間的1/2表示)

7200 rpm的磁盤平均旋轉延遲大約爲60*1000/7200/2 = 4.17ms

10000 rpm的磁盤平均旋轉延遲大約爲60*1000/10000/2 = 3ms

15000 rpm的磁盤其平均旋轉延遲約爲60*1000/15000/2 = 2ms

  1. 數據傳輸時間:忽略不計(由於磁盤是機械運動,浪費的時間主要在尋道和旋轉時間上)

兩部分組成了硬盤隨機訪問數據的時間耗費:

  1. 平均延時:這個時間,其實就是把盤面旋轉,把幾何扇區對準懸臂位置的時間。隨機情況下,平均找到一個幾何扇區,需要旋轉半圈盤面。如:7200 轉的硬盤,那麼一秒裏面,就可以旋轉 240 個半圈。那麼,這個平均延時就是1s / 240 = 4.17ms

  2. 平均尋道時間:也就是在盤面旋轉之後,懸臂定位到扇區的的時間。現在用的 HDD 硬盤的平均尋道時間一般在 4-10ms。

所以可得,隨機在整個硬盤上找一個數據,需要 8-14 ms。一塊 7200 轉的硬盤,一秒鐘隨機的 IO 訪問次數,也就是1s / 8 ms = 125 IOPS 或者 1s / 14ms = 70 IOPS,符合前述HDD 硬盤的 IOPS 每秒 100 次左右。

相應的,如果不是去進行隨機的數據訪問,而是進行順序的數據讀寫,最大化讀取效率就是:我們可以選擇把順序存放的數據,儘可能地存放在同一個柱面上。這樣,我們只需要旋轉一次盤面,進行一次尋道,就可以去寫入或者讀取,同一個垂直空間上的多個盤面的數據。如果一個柱面上的數據不夠,也不要去動懸臂,而是通過電機轉動盤面,這樣就可以順序讀完一個磁道上的所有數據。所以,其實對於 HDD 硬盤的順序數據讀寫,吞吐率還是很不錯的,可以達到 200MB/s 左右。

Linux IO調度(電梯算法)

https://kernel.org/

https://www.thomas-krenn.com/en/wiki/Linux_Storage_Stack_Diagram

Linux內核2.6開始引入了全新的IO調度子系統,IO調度器的總體目標是希望讓磁頭能夠總是往一個方向移動,移動到底了再往反方向走,這恰恰就是現實生活中的電梯模型,所以IO調度器也被叫做電梯。 (elevator)而相應的算法也就被叫做電梯算法。而Linux中IO調度的電梯算法有好如下幾種:as(Anticipatory)、cfq(Complete Fairness Queueing)、deadline、noop(No Operation)。具體使用哪種算法我們可以在啓動的時候通過內核參數elevator來指定,默認使用的算法是cfq。

對於磁盤I/O,Linux提供了cfq, deadline和noop三種調度策略

考慮到硬件配置、實際應用場景(讀寫比例、順序還是隨機讀寫)的差異,實際該選擇哪個基本還是要實測來驗證。不過下面幾條說明供參考:

  • deadline和noop差異不是太大,但它們倆與cfq差異就比較大。

  • MySQL這類數據存儲系統不要使用cfq(時序數據庫可能會有所不同)。

Deadline確保了在一個截止時間內服務請求,這個截止時間是可調整的,而默認讀期限短於寫期限.這樣就防止了寫操作因爲不能被讀取而餓死的現象.Deadline對數據庫環境(ORACLE RAC,MYSQL等)是最好的選擇。

  • 對於虛擬機上面的磁盤,建議採用比較簡單的noop,畢竟數據實際上怎麼落盤取決於虛擬化那一層.

NOOP算法

NOOP算法的全寫爲No Operation。該算法實現了最最簡單的FIFO隊列,所有IO請求大致按照先來後到的順序進行操作。之所以說“大致”,原因是NOOP在FIFO的基礎上還做了相鄰IO請求的合併,並不是完完全全按照先進先出的規則滿足IO請求。

假設有如下的io請求序列:
100,500,101,10,56,1000
NOOP將會按照如下順序滿足:
100(101),500,10,56,1000

NOOP是在Linux2.4或更早的版本的使用的唯一調度算法。由於該算法比較簡單,減了IO佔用CPU中的計算時間最少。不過容易造成IO請求餓死。

NOOP實現了一個簡單的FIFO隊列,它像電梯的工作一樣對I/O請求進行組織,當有一個新的請求到來時,它將請求合併到最近的請求之後,以此來保證請求同一介質.

NOOP傾向餓死讀而利於寫.

NOOP對於閃存設備,RAM,嵌入式系統是最好的選擇.(寫得快,容易插隊)

關於IO餓死的描述如下:因爲寫請求比讀請求更容易。寫請求通過文件系統cache,不需要等一次寫完成,就可以開始下一次寫操作,寫請求通過合併,堆積到I/O隊列中。讀請求需要等到它前面所有的讀操作完成,才能進行下一次讀操作。在讀操作之間有幾毫秒時間,而寫請求在這之間就到來 ,餓死了後面的讀請求 。其適用於SSD或Fusion IO環境下.

Excerpt from ULK3 ch15.3

“ULK3”是“Understanding the Linux Kernel, 3rd Edition”

Unix systems allow the deferred writes of dirty pages into block devices,  
because this noticeably improves system performance. 
Several write operations  on a page in cache could be satisfied by just one slow 
physical update of the  corresponding disk sectors. Moreover, write operations
 are less critical than  read operations, 
because a process is usually not suspended due to delayed  writings, 
while it is most often suspended because of delayed reads. 
Thanks to  deferred writes, each physical block device will service,
on the average, many  more read requests than write ones.

CFQ (Complete Fairness Queueing)算法

該算法的特點是按照IO請求的地址進行排序,而不是按照先來後到的順序來進行響應。CFQ爲每個進程/線程,單獨創建一個隊列來管理該進程所產生的請求,也就是說每個進程一個隊列,各隊列之間的調度使用時間片來調度,以此來保證每個進程都能被很好的分配到I/O帶寬。假設有如下的io請求序列:

100,500,101,10,56,1000
CFQ將會按照如下順序滿足:
100,101,500,1000,10,56

在傳統的SAS盤上,磁盤尋道花去了絕大多數的IO響應時間。CFQ的出發點是對IO地址進行排序,以儘量少的磁盤旋轉次數來滿足儘可能多的IO請求。在CFQ算法下,SAS盤的吞吐量大大提高了。但是相比於NOOP的缺點是,先來的IO請求並不一定能被滿足,也可能會出現餓死的情況,不過其作爲最新的內核版本和發行版中默認的I/O調度器,對於通用的服務器也是最好的選擇。CFQ是deadline和as調度器的折中,CFQ對於多媒體應用(video,audio)和桌面系統是最好的選擇。

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確保了在一個截止時間內服務請求,這個截止時間是可調整的,而默認讀期限短於寫期限。這樣就防止了寫操作因爲不能被讀取而餓死的現象。Deadline對數據庫環境(ORACLE RAC,MYSQL等)是最好的選擇。

ANTICIPATORY(預期)算法

CFQ和DEADLINE考慮的焦點在於滿足零散IO請求上。對於連續的IO請求,比如順序讀,並沒有做優化。爲了滿足隨機IO和順序IO混合的場景,Linux還支持ANTICIPATORY調度算法。ANTICIPATORY的在DEADLINE的基礎上,爲每個讀IO都設置了6ms的等待時間窗口。如果在這6ms內OS收到了相鄰位置的讀IO請求,就可以立即滿足。

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

IO調度配置

查看當前系統支持的IO調度算法

root@harry:~# cat /sys/block/sda/queue/scheduler
noop deadline [cfq]
root@harry:/# cat /sys/block/sda/queue/scheduler 
[mq-deadline] none
root@harry:/# cat /sys/block/sda/queue/scheduler 
[mq-deadline] none

修改調度策略

root@harry:/# echo none > /sys/block/sda/queue/scheduler
root@harry:/# cat /sys/block/sda/queue/scheduler 
[none] mq-deadline 

永久修改調度策略

修改內核引導參數,加入elevator=調度程序名

總結

CFQ和DEADLINE考慮的焦點在於滿足零散IO請求上。對於連續的IO請求,比如順序讀,並沒有做優化。爲了滿足隨機IO和順序IO混合的場景,Linux還支持ANTICIPATORY調度算法。ANTICIPATORY的在DEADLINE的基礎上,爲每個讀IO都設置了6ms的等待時間窗口。如果在這6ms內OS收到了相鄰位置的讀IO請求,就可以立即滿足。

IO調度器算法的選擇,既取決於硬件特徵,也取決於應用場景。

在傳統的SAS盤上,CFQ、DEADLINE、ANTICIPATORY都是不錯的選擇;對於專屬的數據庫服務器,DEADLINE的吞吐量和響應時間都表現良好。然而在新興的固態硬盤比如SSD、Fusion IO上,最簡單的NOOP反而可能是最好的算法,因爲其他三個算法的優化是基於縮短尋道時間的,而固態硬盤沒有所謂的尋道時間且IO響應時間非常短。

參考文章

https://blog.csdn.net/BaiWfg2/article/details/52885287

https://kernel.org/

https://www.thomas-krenn.com/en/wiki/Linux_Storage_Stack_Diagram

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章