linux的IO調度算法和回寫機制

   Linux IO調度程序是塊設備I/O子系統的主要組件,它介於通用塊層和塊設備驅動程序之間,如下圖所示。當Linux內核組件要讀寫數據時,並非一有請求便立即執行,而是將請求放入請求(輸入)隊列,並推遲執行。爲什麼如此設計?原因在於Linux需要應對的最核心的塊設備是磁盤。磁盤的尋道時間嚴重製約磁盤性能,若想提高磁盤IO性能必須想盡辦法減少磁盤尋道次數。

   215218519.png

   塊設備I/O子系統最核心的任務也就是提高塊設備的整體性能,爲此Linux實現了四種IO調度算法,算法基本思想就是通過合併和排序IO請求隊列中的請求大大降低所需的磁盤尋道時間,從而提供整體IO性能。

         2.6內核實現了四種IO調度算法,分別爲預期(Anticipatory)算法、最後期限(Deadline)算法、完全公平對列(CFQ)算法以及NOOP算法(No Operation)。用戶可在內核引導時指定一種I/O調度算法,也可在運行時通過 sysfs 文件系統/sys/block/sda/queue/scheduler改變塊設備的I/O調度算法(cat可查看當前使用IO調度算法)。默認的IO調度程序是CFQ  IO調度程序。

         Noop 算法:

         最簡單的 I/O調度算法。該算法僅適當合併用戶請求,並不排序請求:新的請求通常被插在調度隊列的開頭或末尾,下一個要處理的請求總是隊列中的第一個請求。這種算法是爲不需要尋道的塊設備設計的,如SSD。

         CFQ 算法:

         "CFQ(完全公平隊列)”算法的主要目標是在觸發I/O請求的所有進程中確保磁盤I/O帶寬的公平分配。

         算法使用許多個排序隊列——缺省爲64——它們存放了不同進程發出的請求。

         當算法處理一個請求時,內核調用一個散列函數將當前進程的線程組標識符(PID);然後,算法將一個新的請求插人該隊列的末尾。因此,同一個進程發出的請求通常被插入相同的隊列中。

         算法本質上採用輪詢方式掃描I/O輸入隊列,選擇第一個非空隊列,依次調度不同隊列中特定個數(公平)的請求,然後將這些請求移動到調度隊列的末尾

        Deadline 算法:

         除了調度隊列外,“最後期限”算法還使用了四個隊列。---

         兩個排序隊列分別包含讀請求和寫請求(IO請求是根據起始扇區號排序

         兩個最後期限隊列包含相同的讀和寫請求(根據它們的“最後期限”排序

         引入原因:爲了避免請求餓死,由於電梯策略(曾經的調度算法)優先處理與上一個所處理的請求最近的請求,因而就會對某個請求忽略很長一段時間,這時就會發生這種情況。

         最後期限的本質:就是一個超時定時器,當請求被傳給電梯算法時開始計時。缺省情況下,讀請求的超時時間是500ms,寫請求的超時時間是5s——讀請求優先於寫請求,因爲讀請求通常阻塞發出請求的進程。最後期限保證了調度程序照顧等待很長一段時間的那個請求,即使它位於排序隊列的末尾。

         工作方式:當算法要補充調度隊列時,首先確定下一個請求的數據方向。如果同時要調度讀和寫兩個請求,算法會選擇“讀”方向,除非該“寫”方向已經被放棄很多次了(爲了避免寫請求餓死)。 接下來,算法檢查與被選擇方向相關的最後期限隊列:如果隊列中的第一個請求的最後期限已用完,那麼算法將該請求移到調度隊列的末尾。同時,它也會移動該過期的請求後面的一組來自排序隊列的相同扇區號的請求。如果將要移動的請求在磁盤上物理相鄰,那麼這一批隊列的長度會很長,否則就很短。最後,如果沒有請求超時,算法對來自於排序隊列的最後一個請求連帶之後的一組相同扇區的請求進行調度。當指針到達排序隊列的末尾時,搜索又從頭開始(“單方向算法”)。

       Anticipatory 預期算法

       基本原理:是“最後期限”算法的一個演變,借用了“最後期限”算法的基本機制:兩個最後期限隊列和兩個排序隊列;I/O調度程序在讀和寫請求之間交互掃描排序隊列,不過更傾向於讀請求。

       新特性:有些情況下,算法可能在排序隊列當前位置之後選擇一個請求,從而強制磁頭從後搜索。這種情況通常發生在這個請求之後的搜索距離小於在排序隊列當前位置之後對該請求搜索距離的一半時。

       算法統計系統中每個進程觸發的I/O操作的種類。當剛剛調度了由某個進程p發出的一個讀請求之後,算法馬上檢查排序隊列中的下一個請求是否來自同一個進程p。如果是,立即調度下一個請求。否則,查看關於該進程p的統計信息:如果確定進程p可能很快發出另一個讀請求,那麼就延遲一小段時間(缺省大約爲7ms)。因此,算法預測進程p發出的讀請求與剛被調度的請求在磁盤上可能是“近鄰”。

     

        Linux回寫機制

        頁高速緩存最開始是爲內存管理而設計的,在2.6內核中,各種基於頁的數據管理都納入頁高速緩存。因此塊設備的IO緩衝區也屬於頁高速緩存。需要知道的是:所有文件的IO操作都是“讀寫緩存”。

        對於讀操作,只有當數據不在緩存時才需要IO操作。對於寫操作,一定需要IO操作,但內核把數據寫到高速緩存後write系統調用立馬返回,內核採用特定的寫進程統一回寫dirty的緩存頁。即內核對讀寫是分別對待的:“同步讀,異步寫”!

       Linux的寫回由特定進程按照特定算法來進行回寫。在2.6.32之前的內核,pdflush後臺回寫例程負責完成這個工作。啥時回寫呢? 下面兩種情況下,髒頁會被寫會到磁盤:

       1.在空閒內存低於一個特定的閾值時,內核必須將髒頁寫回磁盤,以便釋放內存。

   2.當髒頁在內存中駐留超過一定的閾值時,內核必須將超時的髒頁寫會磁盤,以確保髒頁不會無限期地駐留在內存中。

   回寫開始後,pdflush會持續寫數據,直到滿足以下兩個條件:    

  1.已經有指定的最小數目的頁被寫回到磁盤。

  2.空閒內存頁已經回升,超過了閾值dirty_background_ration。

  可以在/proc/sys/vm中設置回寫相關的參數,也可以通過sysctl系統調用來設置它們。下表給出了可以設置的量:

       222906342.png

  回寫缺陷:

  1) 回寫不及時引發丟數據(sync|fsync);2) 回寫期間讀IO性能極差,尤其是大數據量時。



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