最近遇到了一塊兒跟磁盤相關的線上故障,藉此總結一下以前不太瞭解的Linux磁盤緩存相關的知識。node
總的來講磁盤緩存出現的緣由大概有兩個:第一是訪問磁盤的速度遠慢於訪問內存的速度,經過在內存中緩存磁盤內容能夠提升訪問速度;第二是根據程序的局部性原理,數據一旦被訪問過,就頗有可能在短期內再次被訪問,因此在內存中緩存磁盤內容能夠提升程序運行速度。算法
程序局部性原理:程序在執行時呈現出局部性規律,即在一段時間內,整個程序的執行僅限於程序中的某一部分。相應地,執行所訪問的存儲空間也侷限於某個內存區域,具體來講,局部性一般有兩種形式:時間局部性和空間局部性。緩存
時間局部性:被引用過一次的存儲器位置在將來會被屢次引用。函數
空間局部性:若是一個存儲器的位置被引用,那麼未來他附近的位置也會被引用。操作系統
Linux系統中爲了減小對磁盤的IO操做,會將打開的磁盤內容進行緩存,而緩存的地方則是物理內存,進而將對磁盤的訪問轉換成對內存的訪問,有效提升程序的速度。Linux的緩存方式是利用物理內存緩存磁盤上的內容,稱爲頁緩存(page cache)。線程
頁緩存是由內存中的物理頁面組成的,其內容對應磁盤上的物理塊。頁緩存的大小會根據系統的內存空閒大小進行動態調整,它能夠經過佔用內存以擴張大小,也能夠自我收縮以緩解內存使用壓力。接口
在虛擬內存機制出現之前,操做系統使用塊緩存系列,可是在虛擬內存出現之後,操做系統管理IO的粒度更大,所以採用了頁緩存機制,頁緩存是基於頁的、面向文件的緩存機制。隊列
Linux系統在讀取文件時,會優先從頁緩存中讀取文件內容,若是頁緩存不存在,系統會先從磁盤中讀取文件內容更新到頁緩存中,而後再從頁緩存中讀取文件內容並返回。大體過程以下:進程
因此說,全部的文件內容的讀取,不管最初有沒有命中頁緩存,最終都是直接來源於頁緩存。內存
由於頁緩存的存在,當一個進程調用write時,對文件的更新僅僅是被寫到了文件的頁緩存中,讓後將對應的頁標記爲dirty,整個過程就結束了。Linux內核會在週期性地將髒頁寫回到磁盤,而後清理掉dirty標識。
因爲寫操做只會把變動寫入頁緩存,所以進程並不會所以爲阻塞直到磁盤IO發生,若是此時計算機崩潰,寫操做的變動可能並無發生在磁盤上。因此對於一些要求比較嚴格的寫操做,好比數據系統,就須要主動調用fsync等操做及時將變動同步到磁盤上。讀操做則不一樣,read一般會阻塞直到進程讀取到數據,而爲了減小讀操做的這種延遲,Linux系統仍是用了「預讀」的技術,即從磁盤中讀取數據時,內核將會多讀取一些頁到頁緩存中。
頁緩存的回寫是由內核中的單獨的線程來完成的,回寫線程會在如下3種狀況下進行回寫:
回寫線程的實現
名稱 | 版本 | 說明 |
---|---|---|
bdflush | 2.6版本之前 | bdflush 內核線程在後臺運行,系統中只有一個 bdflush 線程,當內存消耗到特定閥值如下時,bdflush 線程被喚醒。kupdated 週期性的運行,寫回髒頁。 可是整個系統僅僅只有一個 bdflush 線程,當系統回寫任務較重時,bdflush 線程可能會阻塞在某個磁盤的I/O上,致使其餘磁盤的I/O回寫操做不能及時執行。 |
pdflush | 2.6版本引入 | pdflush 線程數目是動態的,取決於系統的I/O負載。它是面向系統中全部磁盤的全局任務的。 可是因爲 pdflush 是面向全部磁盤的,因此有可能出現多個 pdflush 線程所有阻塞在某個擁塞的磁盤上,一樣致使其餘磁盤的I/O回寫不能及時執行。 |
flusher線程 | 2.6.32版本之後引入 | flusher 線程的數目不是惟一的,同時flusher線程不是面向全部磁盤的,而是每一個flusher線程對應一個磁盤 |
Linux中頁緩存的替換邏輯是一個修改過的LRU實現,也稱爲雙鏈策略。和之前不一樣,Linux維護的再也不是一個LRU鏈表,而是維護兩個鏈表:活躍鏈表和非活躍鏈表。處於活躍鏈表上的頁面被認爲是「熱」的且不會被換出,而在非活躍鏈表上的頁面則是能夠被換出的。在活躍鏈表中的頁面必須在其被訪問時就處於非活躍鏈表中。兩個鏈表都被僞LRU規則維護:頁面從尾部加入,從頭部移除,如同隊列。兩個鏈表須要維持平衡–若是活躍鏈表變得過多而超過了非活躍鏈表,那麼活躍鏈表的頭頁面將被從新移回到非活躍鏈表中,一遍能再被回收。雙鏈表策略解決了傳統LRU算法中對僅一次訪問的窘境。並且也更加簡單的實現了僞LRU語義。這種雙鏈表方式也稱做LRU/2。更廣泛的是n個鏈表,故稱LRU/n。
在此次遇到的線上故障中,根本緣由在於在業務邏輯中使用了臨時文件作緩存,一個臨時文件建立後若是在短期內刪除,這時候對這個文件的操做都是在頁緩存內進行,不會實際回寫到磁盤。當程序出現問題響應變慢時,臨時文件存活時間變長,就可能會使其被回寫到磁盤上,致使磁盤壓力過大,進而影響整個系統。