k8s 最佳實踐:處理內存碎片化
內存碎片化造成的危害
節點的內存碎片化嚴重,導致docker運行容器時,無法分到大的內存塊,導致start docker失敗。最終導致服務更新時,狀態一直都是啓動中
在長時間運行的Linux操作系統中,系統日誌有時會出現無法分配高階內存的報錯信息:
Aug 4 22:58:15 server1 kernel: : [69229257.683658] xenwatch: page allocation failure. order:4, mode:0xd0
Aug 4 22:58:15 server1 kernel: : [69229257.683665] Pid: 168, comm: xenwatch Tainted: GF --------------- 2.6.32-358.23.2.el5.x86_64 #1
Aug 4 22:58:15 server1 kernel: : [69229257.683672] Call Trace:
Aug 4 22:58:15 server1 kernel: : [69229257.683688] [<ffffffff8112723a>] ? __alloc_pages_nodemask+0x67a/0x8c0
Aug 4 22:58:15 server1 kernel: : [69229257.683697] [<ffffffff8126082f>] ? number+0x2ff/0x330
Aug 4 22:58:15 server1 kernel: : [69229257.683706] [<ffffffff81162260>] ? kmem_getpages+0x60/0x150
此時使用cat /proc/buddyinfo
觀察內存order分配情況,可以看到內存碎片化嚴重(大量的低階內存頁,但是幾乎沒有高階內存頁)
#cat /proc/buddyinfo
Node 0, zone DMA 2 2 2 1 2 1 1 0 0 0 2
Node 0, zone DMA32 32995 4377 762 211 157 108 68 23 3 0 0
Node 0, zone Normal 127146 68215 1614 0 0 0 0 0 0 0 1
處理的方法主要採用drop_caches
(拋棄緩存),然後使用compact_memory
合併低階內存頁來創造出足夠的高階內存頁。
方案1:drop_caches
Linux Kernel 2.6.16之後的內核提供了一個設置內核拋棄 頁緩存 和/或
目錄(dentry)和索引節點(inode)緩存,這樣可以釋放出大量內存。
- 釋放頁緩存
echo 1 > /proc/sys/vm/drop_caches
- 釋放目錄和索引節點緩存(inode and dentry cache)
echo 2 > /proc/sys/vm/drop_caches
- 同時釋放 頁、目錄、索引節點緩存:
echo 3 > /proc/sys/vm/drop_caches
上述操作是無害的操作,並且智慧釋放完全沒有使用的內存對象。髒對象(dirty objects)將繼續被使用直到它們被寫入到磁盤中,所以內存髒對象不會被釋放。不過,如果在執行drop_caches
之前執行sync
指令,則會將髒對象刷新到磁盤中,這樣drop_caches
操作會釋放出更多內存。
注意:drop_caches
需要花費一些時間(在終端中可以看到大約幾十秒時間),此時再次使用cat /proc/buddyinfo
可以看到立即出現了大量高階內存頁。
但是drop_caches
這個觸發動作是一次性的,也就是說,並不因爲cat /proc/sys/vm/drop_caches
時顯示輸出內容是3
就表示系統不緩存內容。相反,一旦完成drop_caches
,系統立即自動對後續內存對象進行緩存。所以要再次觸發緩存清理,需要再次執行 echo 3 > /proc/sys/vm/drop_caches
。
如果重複
echo 3 > /proc/sys/vm/drop_caches
不能再次釋放緩存,可以先嚐試echo 0 > /proc/sys/vm/drop_caches
然後再執行echo 3 > /proc/sys/vm/drop_caches
。
方案2:compact_memory 內存整理
當內核編譯參數設置了CONFIG_COMPACTION
,就會在/proc/sys/vm/compact_memory
有入口文件。將1
寫入到這個文件,則所有的zones就會進行壓縮,以便能夠儘可能地提供連續內存塊。對於需要分配大頁的時候這個功能非常重要,不過,進程會在需要時直接進行內存壓縮(compact memory)。
必要時候進行內存整理,開銷會比較大,會造成業務卡住一段時間(慎用):
echo 1 > /proc/sys/vm/compact_memory
實踐案例
- 檢查系統缺乏高階內存
#cat /proc/buddyinfo
Node 0, zone DMA 2 2 2 1 2 1 1 0 0 0 2
Node 0, zone DMA32 32995 4377 762 211 157 108 68 23 3 0 0
Node 0, zone Normal 127146 68215 1614 0 0 0 0 0 0 0 1
- 執行緩存釋放
#echo 3 > /proc/sys/vm/drop_caches
- 完成後檢查內存頁
#cat /proc/buddyinfo
Node 0, zone DMA 2 2 2 1 2 1 1 0 0 0 2
Node 0, zone DMA32 76826 65298 43784 20780 5272 616 90 32 4 0 0
Node 0, zone Normal 524538 365499 176074 45644 4338 140 6 0 0 0 1
- 然後執行內存壓縮
#echo 1 > /proc/sys/vm/compact_memory
- 然後再次檢查內存頁分佈,可以看到逐漸出現更多的高階內存頁
#cat /proc/buddyinfo
Node 0, zone DMA 2 2 2 1 2 1 1 0 0 0 2
Node 0, zone DMA32 18217 13464 8621 4666 2654 2087 1609 1040 517 130 3
Node 0, zone Normal 145048 131183 76864 38454 20405 11854 5149 1143 96 3 1