閱讀270 返回首頁    go 阿裏雲 go 技術社區[雲棲]


手工清理 cgroup中的page cache

標簽

PostgreSQL , Linux , cgroup , limit , page cache , touch


背景

原文

https://blogs.360.cn/360xitong/2013/05/02/mem-cgroup%E7%9B%AE%E5%BD%95%E6%97%A0%E6%B3%95%E6%B8%85%E7%90%86%E9%97%AE%E9%A2%98%E5%88%86%E6%9E%90/

Cgroup(Control Group)是內核提供的資源隔離的技術,用於對Linux 係統中用戶態進程使用的資源進行隔離,核心思想是:把進程分組,然後為進程組分配資源(包括內存、CPU、IO等)。其中Mem Cgroup用來隔離進程組使用的內存資源。

在Hadoop集群中,我們使用了Mem Cgroup對MapReduce任務使用的內存資源進行隔離控製,以保證單個任務不能占用太大的內存,進而保證整個係統的穩定性。同時我們配置了release_agent,用於在mem cgroup中的所有進程退出後清理相關的資源。

但Mem Cgroup在Hadoop集群上線後,經常會出現某個Mem Cgroup中的進程已經全部退出,但對應的Cgroup目錄清理不掉的現象。查看Cgroup的狀態,有如下現象:

[root@]# cat /cgroup/memory/test/tasks  
  
[root@]# cat /cgroup/memory/test/memory.usage_in_bytes  
  
90112  

該cgroup的所有進程確實都已經退出了,但還是存在部分內存處於被使用狀態,這是神馬情況,下意識地想到,難道是Page Cache,果斷驗證下:

echo 3 > /proc/sys/vm/drop_caches  
  
實際上可以直接對CGROUP內的drop_caches進行操作  
  
echo 3 > /cgroup/memory/test/memory.drop_caches  

刷掉Page Cache之後,殘留的cgroup目錄竟然成功被清理了, 那基本斷定是Page Cache的影響了,後麵就得分析下代碼,研究下其中的原理了。

經過幾天的分析,終於把Mem Cgroup的基本原理搞明白了。

在Linux內核中,每個Mem Cgroup都對應一個mem_cgroup結構,該結構的的核心是res_counter,記錄了資源使用情況和資源限製,每個mem cgroup對象都包含一個與之關聯的res_counter。

Linux內核管理內核的基本單位是頁麵,采用page結構管理,一個物理頁框對應著一個page結構,與此同時,新增了一個page_cgroup結構,用來關聯page和mem_cgroup,這樣給定任何一個頁麵,都可以找到對應的mem_cgroup。另外,每個進程都有一個mm_struct結構來管理進程的內存信息。每個mm_struct知道自己屬於的進程,進而可以知道進程所屬的mem_cgroup。

pic

用戶進程物理內存的分配基本都是通過page_fault來實現,現在來看下這個過程中是如何實現mem cgroup相關功能的,page_fault的大體流程如下:

1、根據current進程找到對應的mm_struct結構

2、分配需要的page頁麵

3、調用mem_cgroup_newpage_charge:該函數根據mm struct查找到對應的mem_cgroup,然後判斷下當前mem_cgroup是否已經超過限製,如果沒有,則把新分配page對應page_cgroup指向該mem_cgroup,並更新資源使用計數。如果已經超過了限製,則進行oom相關的處理。

現在來考慮下Page cache,這些內存是係統級的,可以被所有進程使用,那這些內存的使用算在哪個進程的頭上呢?mem cgroup采用的是first touch的原則,就是說哪個進程把page cache頁麵“帶進”內存,這個頁麵就算在誰的頭上。

大致了解了Mem cgroup的原理,回到一開始的問題,雖然mem cgroup中的進程都已經退出了,但是這些進程使用的page cache仍然計算在這個mem cgroup中,導致mem cgroup一直被引用,因此mem cgroup清理不掉,刷掉page cache後,mem cgroup就沒有被引用了,也就可以清理了。

針對該問題,我們在內核新增加了一個page cache的使用計算選擇:把page cache全部算入默認的根mem cgroup。這樣做的另外一個好處是,mem cgroup隻記錄進程本身利用的物理內存,更直觀可控。同時page cache是可回收的,如果某個mem cgroup中的進程產生大量的page cache時,其他mem cgroup進程的內存基本不受影響,可能的壞處是影響其他mem cgroup內存分配的效率。

cgroup內的page cache並不會影響用戶申請內存,當用戶申請的內存超過cgroup剩餘內存時,內核會自動釋放cgroup內的page cache,騰出內存空間給用戶使用。注意RSS的部分是無法被釋放的。

#cat memory.stat   
  
cache 4194889728  
rss 0  
mapped_file 0  
pgpgin 1280316  
pgpgout 256173  
swap 0  
inactive_anon 0  
active_anon 0  
inactive_file 4194332672  
active_file 483328  
unevictable 0  
hierarchical_memory_limit 4294967296  
hierarchical_memsw_limit 9223372036854775807  
total_cache 4194889728  
total_rss 0  
total_mapped_file 0  
total_pgpgin 1280316  
total_pgpgout 256173  
total_swap 0  
total_inactive_anon 0  
total_active_anon 0  
total_inactive_file 4194332672  
total_active_file 483328  
total_unevictable 0  

參考

https://blogs.360.cn/360xitong/2013/05/02/mem-cgroup%E7%9B%AE%E5%BD%95%E6%97%A0%E6%B3%95%E6%B8%85%E7%90%86%E9%97%AE%E9%A2%98%E5%88%86%E6%9E%90/

https://lwn.net/Articles/432224/

最後更新:2017-08-20 17:06:20

  上一篇:go  PostgreSQL 單列多條件查詢優化 - 多個多邊形查詢4倍提升的技巧
  下一篇:go  如何檢測、清理Greenplum垃圾 - 阿裏雲HybridDB for PG最佳實踐