linux核心分析筆記—-頁快取和頁回寫

來源:互聯網
上載者:User
Linux核心塊裝置I/O子系統

Linux IO發送器是塊裝置I/O子系統的主要組件,它介於通用塊層和塊裝置驅動程式之間,如所示。當Linux核心組件要讀寫資料時,並非一有請求便立即執行,而是將請求放入請求(輸入)隊列,並延遲執行。為什麼如此設計?原因在於Linux需要應對的最核心的塊裝置是磁碟。磁碟的尋道時間嚴重製約磁碟效能,若想提高磁碟IO效能必須想盡辦法減少磁碟尋道次數。

塊裝置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發送器是"預測"IO發送器。

“Noop ”演算法

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

“CFQ ”演算法

"CFQ(完全公平隊列)”演算法的主要目標是在觸發I/O請求的所有進程中確保磁碟I/O頻寬的公平分配。為了達到這個目標,演算法使用許多個排序隊列——預設為64——它們存放了不同進程發出的請求。當演算法處理一個請求時,核心調用一個散列函數將當前進程的線程群組識別碼(PID);然後,演算法將一個新的請求插人該隊列的末尾。因此,同一個進程發出的請求通常被插入相同的隊列中。

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

“期限”演算法

除了調度隊列外,“期限”演算法還使用了四個隊列。其中的兩個排序隊列分別包含讀請求和寫請求,其中的請求是根據起始扇區號排序的。另外兩個期限隊列包含相同的讀和寫請求,但這是根據它們的“期限”排序的。引人這些隊列是為了避免請求餓死,由於電梯策略(曾經的調度演算法)優先處理與上一個所處理的請求最近的請求,因而就會對某個請求忽略很長一段時間,這時就會發生這種情況。請求的期限本質上就是一個逾時定時器,當請求被傳給電梯演算法時開始計時。預設情況下,讀請求的逾時時間是500ms,寫請求的逾時時間是5s——讀請求優先於寫請求,因為讀請求通常阻塞發出請求的進程。期限保證了發送器照顧等待很長一段時間的那個請求,即使它位於排序隊列的末尾。

當演算法要補充調度隊列時,首先確定下一個請求的資料方向。如果同時要調度讀和寫兩個請求,演算法會選擇“讀”方向,除非該“寫”方向已經被放棄很多次了(為了避免寫請求餓死)。

接下來,演算法檢查與被選擇方向相關的期限隊列:如果隊列中的第一個請求的期限已用完,那麼演算法將該請求移到調度隊列的末尾。同時,它也會移動該到期的請求後面的一組來自排序隊列的相同扇區號的請求。如果將要移動的請求在磁碟上物理相鄰,那麼這一批隊列的長度會很長,否則就很短。

最後,如果沒有請求逾時,演算法對來自於排序隊列的最後一個請求連帶之後的一組相同扇區的請求進行調度。當指標到達排序隊列的末尾時,搜尋又從頭開始(“單方向演算法”)。

“預期”演算法

“預期”演算法是Linux提供的最複雜的一種1/O調度演算法。基本上,它是“期限”演算法的一個演變,借用了“期限”演算法的基本機制:兩個期限隊列和兩個排序隊列;I/O發送器在讀和寫請求之間互動掃描排序隊列,不過更傾向於讀請求。掃描基本上是連續的,除非有某個請求逾時。讀請求的預設逾時時間是125ms,寫請求的預設逾時時間是250ms。但是,該演算法還遵循一些附加的啟發學習法準則:

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

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

linux的回寫機制

不管如何最佳化塊裝置調度演算法,也不可能解決磁碟IO和CPU速度嚴重不匹配的問題,為此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系統調用來設定它們。下表給出了可以設定的量:

回寫機制看上去很完美,在實際工作中卻未必。一個問題是:pdflush線程資料是可變的(2-8),但面對的是所有塊裝置的資料,當某個塊裝置很慢,必然阻塞其他塊裝置的回寫。為此2.6.32引入新的pdflush執行緒模式,每個塊裝置擁有獨立的pdflush線程,裝置之間的回寫不再互相干擾。

回寫缺陷

看上去如此完美的回寫機制,實際中有2個缺陷:1) 回寫不及時引發丟資料(sync|fsync);2) 回寫期間讀IO效能極差,尤其是大資料量時。

Linux:2.6.16 
記憶體:32G
測試過程:限速情況下持續追加寫入磁碟,速度20-10MB/s, 
實測曲線:

結論:pdflush回寫期間極其消耗磁碟IO,嚴重影響讀效能。

相關文章

linux kernel development 3rd(Linux核心設計與實現)

塊裝置I/O發送器

linux核心分析筆記----頁快取和頁回寫

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.