使用大量可用記憶體進行永久交換
我們有一台執行 Debian 4.0.5(核心 4.0.0-2)的 Linux 伺服器,安裝了 32G RAM 並配置了 16G Swap。該系統使用 lxc 容器進行分隔,但這在這裡無關緊要。該問題存在於不同容器的內部和外部。
這是一個典型的
free -h
:total used free shared buff/cache available Mem: 28G 2.1G 25G 15M 936M 26G Swap: 15G 1.4G 14G
/proc/meminfo
擁有Committed_AS: 12951172 kB
所以有足夠的可用記憶體,即使分配的所有內容實際上都是一次使用的。但是,系統會立即對正在執行的程序進行分頁。
這在 Gitlab 中最為顯著,這是一個使用 Unicorn 的 Rails 應用程序:新分叉的 Unicorn 工作人員會立即交換,並且當需要以約 1400kB/s 的速度從磁碟讀取請求時(數據來自
iotop
)並超時(目前為 30 秒) , 讓它及時重啟。正常的請求在完全載入到記憶體之前不應該超過 5s),從而被立即殺死。請注意,這只是一個範例,我在 redis、amavis、postgres、mysql、java(openjdk) 和其他人身上看到過這種情況。否則係統處於低負載狀態,CPU 使用率約為 5%,loadavg 約為 2(在 8 個核心上)。
我們嘗試了什麼(沒有特別的順序):
swapoff -a
:在大約 800M 處失敗仍然交換- 使用 . 減少交換性(逐步)
sysctl vm.swappiness=NN
。這似乎根本沒有影響,我們下降到 0% 並且仍然存在完全相同的行為- 停止非必要服務(Gitlab,一個基於 Jetty 的 web 應用程序…),釋放 ca。8G 已送出但未映射的記憶體,並將 Committed_AS 降至 5G 左右。完全沒有變化。
- 使用 清除系統記憶體
sync && echo 3 > /proc/sys/vm/drop_caches
。這釋放了記憶體,但對交換情況沒有任何作用。- 以上的組合
重新啟動機器以通過 fstab 完全禁用交換作為測試並不是一個真正的選擇,因為某些服務存在可用性問題並且需要計劃的停機時間,而不是“四處尋找”……而且我們真的不想禁用交換作為倒退。
我不明白為什麼這裡會發生任何交換。任何想法可能會發生什麼?
這個問題已經存在了一段時間,但它首先出現在高 IO 負載期間(長時間的後台數據處理任務),所以我無法確定具體事件。這項任務完成了幾天,問題仍然存在,因此這個問題。
記住我是怎麼說的:
該系統使用 lxc 容器進行分隔,但這在這裡無關緊要。
好吧,事實證明這很重要。或者更確切地說,lxc 核心的 cgroups 很重要。
主機只看到核心升級的重啟。那麼,最後使用的核心是什麼?3.19,兩個月前被 4.0.5 取代,昨天被 4.1.3 取代。昨天發生了什麼?程序在左側、右側和中間被 memkilled。檢查
/var/log/kern.log
,受影響的程序在具有 512M 記憶體的 cgroups 中。等等,512M?那不可能是正確的(當預期的要求是 4G 左右時!)。事實證明,這正是我們在幾個月前進行設置時在 lxc 配置中配置的內容。所以,發生的事情是 3.19 完全忽略了 cgroups 的記憶體限制;如果 cgroup 需要超過允許的數量,4.0.5 總是分頁(這是這個問題的核心問題),並且只有 4.1.3 會進行完整的 memkiller-sweep。
主機系統的 swappiness 對此沒有影響,因為它永遠不會接近物理內存不足。
解決方案:
對於臨時更改,您可以直接修改 cgroup,例如對於名為
box1
cgroup的 lxc 容器lxc/box1
,您可以執行(在主機中以 root 身份):$ echo 8G > /sys/fs/cgroup/memory/lxc/box1/memory.limit_in_bytes
永久的解決方案是正確配置容器
/var/lb/lxc/...
lxc.cgroup.memory.limit_in_bytes = 8G
**故事的寓意:**始終檢查您的配置。即使您認為這不可能是問題(並且核心中存在不同的錯誤/不一致實際上會失敗)。