手工清理 cgroup中的page cache
標簽
PostgreSQL , Linux , cgroup , limit , page cache , touch
背景
原文
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。
用戶進程物理內存的分配基本都是通過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://lwn.net/Articles/432224/
最後更新:2017-08-20 17:06:20