《Linux核心技術實戰課》總結一:PageCache

木棉上的光發表於2020-12-12

總覽

Page Cache:核心管理的記憶體

場景:伺服器的 load 飆高; 伺服器的 I/O 吞吐飆高; 業務響應時延出現大的毛刺; 業務平均訪問時延明顯增加

應用程式產生Page Cache的邏輯示意圖,是在應用程式讀寫檔案的過程中產生的
在這裡插入圖片描述

產生,即被分配:有兩種方式
1 標準 I/O 是寫的 (write) 使用者緩衝區 (Userpace Page 對應的記憶體),然後再將使用者緩衝區裡的資料拷貝到核心緩衝區 (Pagecache Page 對應的記憶體);如果是讀的 (read) 話則 是先從核心緩衝區拷貝到使用者緩衝區,再從使用者緩衝區讀資料,也就是 buffer 和檔案內容不存在任何對映關係
2 儲存對映 I/O 而言是直接將 Pagecache Page 給對映到使用者地址空間,使用者直接讀寫 Pagecache Page 中內容。
在這裡插入圖片描述
產生例子:首先往使用者緩衝區 buffer( Userspace Page) 寫入資料, 然後 buffer 中的資料拷貝到核心緩衝區(Pagecache Page),如果核心緩衝區中還沒有這個 Page,就會發生 Page Fault 會去分配一個 Page,拷貝結束後該 Pagecache Page 是一個 Dirty Page(髒頁),然後該 Dirty Page 中的內容會同步到磁碟,同步到磁碟後,該 Pagecache Page 變為 Clean Page 並且繼續存在系統中
在這裡插入圖片描述

死亡,即被回收:應用在申請記憶體的時候,即使沒有 free 記憶體,只要還有足夠可回收的 Page Cache,就可以通過回收 Page Cache 的方式來申請到記憶體;回收的方式主要是兩種:直接回收和後臺回收,可以使用sar -B 1命令 或者 /proc/vmstat 來觀察
在這裡插入圖片描述

問題排查:Linux 核心主要是通過 /proc 和 /sys 把系統資訊匯出給使用者, 可以去這兩個目錄下讀取一下系統資訊,看看哪些指標異常

處理Page Cache難以回收產生的load飆高問題

總體思路是提前回收、加強回收能力

  • 直接記憶體回收引起的 load 飆高

直接記憶體回收是在程式申請記憶體的過程中同步進行的回收,而這個回收過程可能會消 、耗很多時間,進而導致程式的後續行為都被迫等待,這樣就會造成很長時間的延遲,以及 系統的 CPU 利用率會升高,最終引起 load 飆高;
在開始記憶體回收後,首先進行後臺非同步回收(藍色標記的地 方),這不會引起程式的延遲;如果後臺非同步回收跟不上進行記憶體申請的速度,就會開始同步阻塞回收,導致延遲(紅色和粉色標記的地方,這就是引起 load 高的地址):
在這裡插入圖片描述

解決方案:及早地觸發後臺回收來避免應用程式進行直接記憶體回收,通過調高min_free_kbytes引數即可

  • 系統中髒頁積壓過多引起的 load 飆高

直接回收過程中,如果存在較多髒頁就可能涉及在回收過程中進行回寫,這可能會造成非常大的延遲,而且因為這個過程本身是阻塞式的,所以又可能進一步導致系統中處於 D 狀態的程式數增多,最終的表現就是系統的 load 值很高;
如果系統中既有快速 I/O 裝置,又有慢速 I/O 裝置(比如圖中的 ceph RBD 裝置,或者其他慢速儲存裝置比如 HDD),直接記憶體回收過程中遇到了正在往慢速 I/O 裝置 回寫的 page,就可能導致非常大的延遲:
在這裡插入圖片描述

解決方案:控制好系統中積壓的髒頁資料,可以通過 sar -r 來觀察系統中的髒頁個數

  • 系統 NUMA 策略配置不當引起的 load 飆高

系統中如果還有一半左右的 free 記憶體,但還是頻頻觸發 direct reclaim(直接回收),導致業務抖動得比較厲害,那麼可以先看看是否設定了 zone_reclaim_mode,是的話可以先設定為0

可以利用 linux 的 tracepoint 來有效地衡量業務延遲問題是否由 zone reclaim 引起的、它引起的延遲究竟有多大

處理Page Cache容易回收引起的業務效能問題

總體思路:保護重點資料

  • 誤操作而導致 Page Cache 被回收掉,進而導致業務效能下降明顯

drop_cache導致:比如執行2,雖然只想清掉slab,但是因為清掉了inode,會導致無法通過inode去PageCache去查詢檔案(因為如果 inode 被回收的話,那麼它對應的 Page Cache 也都會被回收掉)
在這裡插入圖片描述

可以通過 grep drop /proc/vmstat來檢視drop操作的執行情況

  • 核心的一些機制導致業務 Page Cache 被回收,從而引起效能下降

記憶體回收圖:Reclaimer 是指回收者,它可以是核心執行緒(包括 kswapd) 也可以是使用者執行緒;
回收的時候,它會依次來掃描 pagecache page 和 slab page 中有哪 些可以被回收的,如果有的話就會嘗試去回收,如果沒有的話就跳過。在掃描可回收 page 的過程中回收者一開始掃描的較少,然後逐漸增加掃描比例直至全部都被掃描完:
在這裡插入圖片描述

Reclaim Slab容易出“誤操作”裡描述的問題,可以通過grep inodesteal /proc/vmstat來檢視回收的過程中,因為回收 inode 而釋放的 pagecache page 個數

解決方案:
1 從應用程式碼層面來優化:可以明確地來對讀寫檔案過程中產生的 Page Cache 區 別對待;比如說,對於重要的資料,可以通過 mlock來保護它,防止被回收以及被 drop(可通過egrep “Unevictable|Mlocked” /proc/meminfo來觀察);對於不重要的資料(比如日誌),那可以通過 madvise告訴核心來立即釋放這 些 Page Cache
2 從系統層面來調整:在有些情況下,對應用程式而言,修改原始碼是件比較麻煩的事,Linux 核心實現了不改應用程式的原始碼而從系統層面調整來保護重要資料的機制,叫做memory cgroup protection,其原理就是將需要保護的應用程式使用 memory cgroup 來保護起來,這樣該應用 程式讀寫檔案過程中所產生的 Page Cache 就會被保護起來不被回收或者最後被回收
在這裡插入圖片描述

判斷問題是否由PageCache引起

問題分析總思路:
在這裡插入圖片描述

  • 系統現在 load 很高,是由 Page Cache 引起的嗎?(實時問題排查)

除了Page Cache,還可能是鎖衝突太厲害、物理資源(CPU、記憶體、磁 盤 I/O、網路 I/O)有爭搶、核心特性設計缺陷等等導致的

首先使用 sar 來採集 Page Cache 的概況,其PSI資訊的 avg10 一列表示最近 10s 記憶體的平均壓力情況,如果它很大(比如 大於 40)那 load 飆高大概率是由於記憶體壓力,尤其是 Page Cache 的壓力引起的

接下來需要知道是什麼行為導致PageCache壓力大,也就是看看以下指標是否有異常:
在這裡插入圖片描述

除此之外,有時候還需要知道是什麼東西在進行連續記憶體的申請,可以通過tracepoint來分析:
在這裡插入圖片描述

  • 系統 load 值在昨天飆得很高,是由 Page Cache 引起的嗎?(歷史問題排查)

可以根據 sar 的日誌資訊來判斷當時發生了什麼事情

相關文章