Stories

Detail Return Return

OOM 殺進程 or 應用卡頓?該如何抉擇 - Stories Detail

背景

近期,大量用户反饋系統在運行過程中出現 CPU 利用率與系統負載(load)突發性飆升,甚至引發系統短時卡頓(持續數秒至數十秒)的問題;對於業務來説,輕則導致幾百毫秒的抖動,重則連機器都無法ssh上去。經分析發現,此類異常現象普遍存在一個顯著特徵:均發生在系統內存佔用率接近閾值(90%-95%)時。用户就發出了靈魂拷問:
“水位這麼高了,為什麼內核不觸發 OOM 殺掉一些進程來釋放內存?"
“我寧願內核OOM 把我業務進程殺了,我也不希望應用卡頓和系統夯機影響我其他業務!”
其實這個現象的核心原因就是:內核想確保應用實在沒內存用了才 OOM。
思想總體是正確的,但是一條思想要滿足所有場景也是非常難的。

為什麼還不 OOM?

內存水位這麼高,為什麼還不 OOM!其實主要是由於系統進入了 Near-OOM 狀態。現在,我們先回顧一下 Linux 的內存回收機制,如下圖所示:
image.png
(圖/Linux 內存水線)

Linux 劃分了 high、low、min 三個內存水線。當系統剩餘內存低於 low 水線後,內核會喚醒 kswapd 進程會被喚醒開始進行異步的內存回收,此時對系統沒什麼影響;系統剩餘內存低於 min 水線後,內核會阻塞要分配的內存進程嘗試儘可能地回收所有可回收的內存(主要是文件緩存以及一些內核結構體緩存),回收的過程中可能涉及到將文件緩存寫入磁盤或遍歷一些內核結構體,從而導致系統負載飆高、應用被阻塞。如果能成功回收內存並滿足申請需求則不觸發 OOM。

更糟糕的是,系統可能進入一種 Near-OOM 的活鎖狀態,即內核一邊在嘗試回收文件緩存;但是應用運行過程中從磁盤加載代碼段等行為也在不斷產生文件緩存,那麼就會使整個系統負載持續飆高,甚至發生夯機。

所以,內核 OOM 的策略在業務延時敏感的場景,還是太保守了。

那麼如果我們希望寧願 OOM 把我業務進程殺了,我也不希望應用卡頓和系統夯機影響我其他業務?還有什麼辦法呢?

新 OOM 方案

為了應對 Near-OOM 現象,核心就是“快” OOM,在內核還在猶豫要不要 OOM 的時候,我們就替他做出決定!目前業界已有的方案主要是通過用户態提前殺死相關進程來提前釋放內存,比如應用較為廣泛的是 Facebook(Meta)推出的 oomd。oomd 目前已經集成於 systemd 中成為 systemd-oomd,且從 Ubuntu 22.04 開始集成於 Ubuntu 中。但是 oomd 方案存在以下問題:

  • 與 cgroupV2 以及 Linux 內核的 PSI(Pressure Stall Information)特性深度綁定。但 cgroupV1 目前仍然是雲計算中主流 cgroup 版本,且由於 PSI 功能有一定的性能開銷,在大部分雲計算場景中都是默認關閉的。
  • 只支持以 cgroup 為粒度殺進程,配置 cgroup 級別的殺進程策略。

所以 oomd 在適用性和靈活性上仍有欠缺。

為了解決上述問題,阿里雲操作系統控制枱推出了 FastOOM 功能,支持節點以及 Pod 級別的用户態 OOM 配置,通過提前介入殺進程的方式避 Near-OOM 導致的抖動夯機。

FastOOM 同樣採取用户態提前殺進程的形式來避免系統進入 Near-OOM 狀態,主要分為採集預測模塊和 kill 模塊:採集預測模塊會從阿里雲自研操作系統中讀取內存壓力相關的指標,通過統計學方法對 OOM 發生的概率進行實時預測並判定當前節點或 pod 是否達到相應的內存壓力或即將進入 Near-OOM 狀態。kill 模塊會根據用户配置的殺進程策略,選取對應的進程殺死。

最終所有由 FastOOM 執行的 kill 操作事件都會上報到控制枱中心端進行展示,讓用户方便了解底層的實際操作(不用擔心 FastOOM 偷偷殺死了其他進程)。
image.png

使用 FastOOM 避免 Near-OOM 系統夯機抖動

場景一:配置節點級別策略解決系統Near-OOM抖動夯機問題

客户遇到的問題

某汽車行業發現某實例上業務長時間無響應、登錄實例也十分卡頓。通過監控發現客户實例使用的內存在某個時間點開始徒增,接近系統的總內存(即 available 非常低),但沒有超過系統總內存。
image.png

通過 top 命令可以看到系統的 CPU sys 利用率和 iowait 利用率和系統負載都持續飆高,kswapd0 線程佔用非常高的 CPU 進行內存回收。

image.png

解決方案

通過配置開啓節點級別的 FastOOM 功能,由於業務是實驗較為敏感的業務,內存壓力選擇中,且設置業務程序(以 python 啓動,進程名包含 python 子串)為避免被 OOM 進程且設置無關的日誌程序優先殺死。
image.png

開啓後,當節點內存水位處於 Near-OOM 狀態時,用户態提前介入,根據配置殺死了如下進程,從而釋放了部分內存避免系統進入了夯機狀態。通過操作系統控制枱的系統概覽可以看到 FastOOM 介入的相關記錄。

如下圖所示,由於 kube-rbac-proxy 和 node_exporter 等進程 oom_score_adj 被設置為接近 999,FastOOM 會匹配內核策略優先殺死這些進程,但是由於殺死這些進程後釋放內存較小,仍處於 Near-OOM;因此 FastOOM 殺死了配置優先殺死的 logcollect 進程。
image.png

由於用户態及時介入殺死進程釋放出內存,使系統避免進入了 Near-OOM 的抖動狀態。

案例二:配置Pod級別策略解決Pod應用抖動夯機問題

客户遇到的問題

在 Kubernetes 環境中,我們是可以為 Pod 中的容器配置對應的內存限制的,和節點 OOM 同理,如果 Pod 中的內存使用接近限制時,內核也會嘗試回收 Pod 中所有可回收內存,才觸發 OOM,這時候也會導致 Pod 內業務進程的延時阻塞。

某大數據客户會部署一些延時敏感的業務 Pod(即 Pod 中運行了多個業務進程)。業務時不時會存在響應長尾延時,但是網絡相關指標一切正常。

後面我們接手問題後,通過 Alibaba Cloud Linux 自研指標(該指標反映容器由於內存回收阻塞的時長)發現,存在非常高的內存回收延時,且時間節點和抖動時間匹配:

image.png

推薦客户配置 Pod 級別的 FastOOM 後,通過提前殺死 Pod 中的相關內存佔用進程,避免了內存回收延時的發生,抖動也不再出現。

解決方案

操作系統控制枱提供較為靈活的 Pod 級別的 OOM 殺進程策略配置,可以靈活配置 Pod 中容器內發生 OOM 時,避免和優先殺死的進程。

假設在集羣中通過名為 test-alinux 的 daemonset 在每一個節點部署了對應的 Pod。

image.png

在操作系統控制枱中設置 Pod 級別 FastOOM 策略:

  • 為了匹配對應的 Pod,Pod 名稱填寫 test-alinux(正則表達式會匹配不同節點上的 test-alinux-xxx pod),命名空間為 default。
  • 由於只是希望控制 OOM 時的殺進程策略,將內存壓力級別設置為高,則觸發用户態 OOM 的時機會近似於內核 OOM 的時機。
  • 對於殺進程策略:配置優先殺死特定進程和避免殺死業務進程和 Pod 中的 1 號進程,從而避免 Pod 重啓或影響業務,設置完成後下發至特定節點。

image.png

將配置下發到對應節點後,當 Pod 中容器內存使用超過容器 limit 後,發生 OOM;可以通過操作系統控制枱系統概覽看到 FastOOM 事件記錄,可以看到 FastOOM 根據策略殺死了對應的進程,也避免了特定進程被殺死。

image.png

總結

人無完人,內核的 OOM 其實也不是萬能的。為了能儘可能的回收內存,內核在發生 OOM 前會阻塞申請內存的進程,並嘗試回收內存,這對於延時敏感的業務的影響是非常大的;如果內存持續保持在接近 OOM 的水位,還會進入 Near-OOM 的活鎖狀態導致整機夯機。阿里雲操作系統控制枱的 FastOOM 功能,通過相關指標,支持節點/容器/Pod 級策略,可精準殺指定進程,輕鬆彌補了內核 OOM 帶來的延時卡頓問題。

聯繫我們

您在使用操作系統控制枱的過程中,有任何疑問和建議,可以搜索羣號:94405014449 加入釘釘羣反饋,歡迎大家掃碼加入交流。

阿里雲操作系統控制枱PC端鏈接:https://alinux.console.aliyun.com/

user avatar XY-Heruo Avatar ayuan01 Avatar zdyz Avatar
Favorites 3 users favorite the story!
Favorites

Add a new Comments

Some HTML is okay.