linux pagecache限制與查看


在linux服務器使用過程中,由於linux對內存的使用原則是能cache就盡量cache,所以會出現pagecache占用很多的情況。

suse的版本有一個pagecachelimit的功能,centos中沒有看到。即便是將這個功能合入到centos中,也會發現設置了沒效果的情況。

cat /proc/sys/vm/pagecache_limit_mb 
0

1.將0改為對應的值,比如說12000,限制為120G,我們來看對應的內核中算法為什么沒有生效,

page cache總數 > 8*free_pages + pagecache_limit_mb

算法的關鍵是判斷是否需要進行pagecache限制觸發的回收,當pagecache設置某個值之后,系統中並不是直接以這個值作為判斷標志,而是加上了free的限制,

從這個意義上說,因為設置的pagecache_limit_mb比較少,但是當free很多的時候,是比較難觸發這個條件的。那么要加大回收還有哪些手段?下面針對讀和寫兩個方面來描述。

2.是通過修改/proc/sys/vm/dirty_background_ration以及/proc/sys/vm/dirty_ratio兩個參數的大小來實現回收。

這種場景針對的是很多寫的情況:vm.dirty_background_ratio:這個參數指定了當文件系統緩存臟頁數量達到系統內存百分之多少時(如5%)就會觸發pdflush/flush/kdmflush等后台回寫進程運行,將一定緩存的臟頁異步地刷入外設;

vm.dirty_ratio:而這個參數則指定了當文件系統緩存臟頁數量達到系統內存百分之多少時(如10%),系統不得不開始處理緩存臟頁(因為此時臟頁數量已經比較多,為了避免數據丟失需要將一定臟頁刷入外存);在此過程中很多應用進程可能會因為系統轉而處理文件IO而阻塞。

為什么需要兩個比例?之前一直錯誤的認為dirty_ratio的觸發條件不可能達到,因為每次肯定會先達到vm.dirty_background_ratio的條件,后來根據業務現象,發現不是如此。確實是先達到vm.dirty_background_ratio的條件然后觸發flush進程進行異步的回寫操作,但是這一過程中應用進程仍然可以進行寫操作,如果多個應用進程寫入的量大於flush進程刷出的量那自然有可能達到vm.dirty_ratio這個參數所設定的坎,此時操作系統會轉入同步地處理臟頁的過程,可能阻塞應用進程。

3.針對流媒體使用的時候,寫臟頁不多,大多數是讀的場景,大多是sendfile或者read引起了很多文件進入cache,但是這些文件被繼續訪問的概率很低,所以相當於是一次性使用,之后相當長的時間之內是不會再使用的,所以我們對於pagecache限制的需求很強烈,由於內核本身就有根據水線來動態回收page cache的功能,因此問題的根源可能還在於默認情況下min和low水線間隔太近,導致當free內存低於low水線后,發起的kswapd回收太慢,無法跟上臨時大量內存申請的節奏,從而free內存很快突破min水線,造成內存申請過程中進行cache回收或是申請失敗,從而引起性能問題

因此解決問題的辦法之一,可以通過加大min和low水線之間的間隔來實現

內核剛好提供了這樣一個參數,即/proc/sys/vm/extra_free_kbytes,設置該參數后將拉大min和low水線的間隔,從而保證有足夠的空閑內存來應對臨時大量的內存動態申請。

4.加大水線,提高水線有助於提前觸發回收,這樣相當於后面的內存需求,能從時間上更快觸發回收,但是當你的內存消耗速度大於內存回收的速度,還是會cahce很多,kswap很高。

5.如果還是回收不及時的話,那么需要將kswap的nice級別調低,也有一些幫助,renice設置為-20,雖然從調度上來說它還是低於實時進程,但是比調整前級別高了些。

6.使用posix_madvise,madvise,fadvise,利用POSIX_MADV_DONTNEED特性,但也不能調用太多,容易引起sys沖高,大家在測試的時候,可以分別對訪問幾M之后做清理,找到最佳的設置點。

7.修改系統調用,帶入一個特性值進入,使得系統得知不放入cache,這個和directio的區別是,盡量不要拷貝到用戶態,要區分應用場景,因為directio目前還不支持sendfile這種調用,需要多一次拷貝,也就是雖然節省了查找address_space中的radix樹的流程,但是多了一次內核到用戶態的內存拷貝。當然,我曾經嘗試將directio變成支持sendfile,因為sendfile是基於splice的調用,而原來的directio的流程中,是將用戶的頁面作為寫入地址的,所以需要將directio中對頁面的檢查部分進行定制修改,主要修改pmd的映射。

8.如果是內存化的存儲介質,也就是可以按字節尋址的存儲介質,則可以開啟DAX特性,mount掛載的時候,帶上該特性,這樣就繞過了pagecache。

9.這個是對6的改進,有一定的特殊性,在加入radix樹之前,主動調用 invalidate_mapping_pages ,這個比在用戶態釋放麻煩些,但是效果更好。

 

 如果大家有更好的辦法,希望能提醒一下我。

另外,cache里面保持了哪些內容,這個問題經常會被問到。

這里要提到兩個工具,一個是vmtouch,另外一個是hcache,源碼我就不貼了,有興趣的可以去網上下載。

lsof |grep REG|grep mnt|sort -u |awk '{print $9}'|xargs vmtouch

這個會將我們應用場景下cache占用的文件累計起來,大家要使用的話需要根據文件名稱過濾一下。前提是這個文件的句柄還在被pid所持有,有的文件fd已經關閉,但是還是在系統中存放,那么這個方法是獲取不到的。

除了這兩個工具查看,還有slab的占用要算在里面,

SlabInfo=`cat /proc/slabinfo |awk 'BEGIN{sum=0;}{sum=sum+$3*$4;}END{print sum/1024/1024}'`

 

常見的還有另外一個問題,就是熱點文件的訪問,當時我的處理思路是,每隔一段時間,取一下lsof,然后對比前后兩個文件。

#!/bin/bash

sum=0;

while read line
do
  if [ $(grep $line $2|wc -l) -eq 1 ]
  then
    echo $line >>$1_2_$2.txt
    sum=$(($sum+1))
  fi
done < $1
 echo "sum=$sum"

sum的個數就是前后相同的文件個數,不太精確,因為文件有打開就有關閉,但是多次取樣的話,效果還可以。

 

有的應用場景會盡量不要pagecache,比如視頻點播,但是又不能用dio讀,因為dio讀有對齊要求,而且沒法預讀,常用的辦法是在用戶態取dropcache,但這個dropcache不分青紅皂白,

所以我們在內核態改造成了對某些特定格式,特定大小,特定訪問時間的進行drop,效果比較好。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM