本文發表於一年多前。舊文章可能包含過時內容。請檢查頁面中的資訊自發布以來是否已變得不正確。
Kubernetes Memory Manager 進入 Beta 階段
這篇博文解釋了《記憶體管理器》的一些內部原理,這是 Kubernetes 1.22 的一項 Beta 功能。在 Kubernetes 中,記憶體管理器是 kubelet 的一個子元件。記憶體管理器為 Guaranteed
QoS 類中的 Pod 提供有保障的記憶體(和大頁)分配。
這篇博文涵蓋以下內容:
為什麼您需要它?
一些 Kubernetes 工作負載執行在具有 非統一記憶體訪問 (NUMA) 的節點上。假設您的叢集中存在 NUMA 節點。在這種情況下,您會了解當計算資源需要訪問不同 NUMA 本地記憶體時,可能存在的額外延遲。
為了讓您的工作負載獲得最佳效能和最低延遲,容器的 CPU、外圍裝置和記憶體都應該對齊到相同的 NUMA 本地。在 Kubernetes v1.22 之前,kubelet 已經提供了一套管理器來對齊 CPU 和 PCI 裝置,但您沒有辦法對齊記憶體。Linux 核心能夠盡力從容器執行所在的相同 NUMA 節點為任務分配記憶體,但不能保證這種放置。
它是如何工作的?
記憶體管理器主要做兩件事:
- 向拓撲管理器提供拓撲提示
- 為容器分配記憶體並更新狀態
Kubelet 中記憶體管理器的整體順序
在准入階段
- 在首次處理新 Pod 時,kubelet 呼叫 TopologyManager 的
Admit()
方法。 - 拓撲管理器會為包括記憶體管理器在內的每個提示提供者呼叫
GetTopologyHints()
。 - 記憶體管理器會計算 Pod 中每個容器的所有可能的 NUMA 節點組合,並將提示返回給拓撲管理器。
- 拓撲管理器會為包括記憶體管理器在內的每個提示提供者呼叫
Allocate()
。 - 記憶體管理器根據拓撲管理器選擇的提示,在狀態下分配記憶體。
在 Pod 建立期間
- kubelet 呼叫
PreCreateContainer()
。 - 對於每個容器,記憶體管理器查詢它為容器分配記憶體的 NUMA 節點,然後將該資訊返回給 kubelet。
- kubelet 使用包含記憶體管理器資訊的容器規範,透過 CRI 建立容器。
我們來談談配置
預設情況下,記憶體管理器以 None
策略執行,這意味著它將放任自流,不執行任何操作。要使用記憶體管理器,您應該為 kubelet 設定兩個命令列選項:
--memory-manager-policy=Static
--reserved-memory="<numaNodeID>:<resourceName>=<quantity>"
--memory-manager-policy
的值很簡單:Static
。決定 --reserved-memory
的具體值需要更多思考。要正確配置它,您應該遵循兩個主要規則:
- 為
memory
資源預留的記憶體量必須大於零。 - 為資源型別預留的記憶體量必須等於 節點可分配量 (
kube-reserved + system-reserved + eviction-hard
)。您可以閱讀 為系統守護程序預留計算資源 以瞭解更多關於記憶體預留的資訊。
當前限制
1.22 版本及晉升到 beta 階段帶來了增強和修復,但記憶體管理器仍有幾項限制。
單 NUMA 節點與跨 NUMA 節點分配
NUMA 節點不能同時擁有單 NUMA 節點分配和跨 NUMA 節點分配。當容器記憶體固定在兩個或更多 NUMA 節點時,我們無法知道容器將從哪個 NUMA 節點消耗記憶體。
container1
在 NUMA 節點 0 上啟動,請求 5Gi 記憶體,但目前僅消耗 3Gi 記憶體。- 對於 container2,記憶體請求為 10Gi,並且沒有單個 NUMA 節點可以滿足它。
container2
從 NUMA 節點 0 消耗了 3.5Gi 記憶體,但是一旦container1
需要更多記憶體,它將無法獲得,核心將殺死其中一個容器並報錯 OOM。
為了防止此類問題,記憶體管理器將拒絕 container2
的准入,直到機器擁有兩個沒有單 NUMA 節點分配的 NUMA 節點。
僅適用於 Guaranteed Pod
記憶體管理器無法保證 Burstable Pod 的記憶體分配,即使 Burstable Pod 指定了相同的記憶體限制和請求。
假設您有兩個 Burstable Pod:pod1
中的容器具有相同的記憶體請求和限制,而 pod2
中的容器僅設定了記憶體請求。您希望為 pod1
保證記憶體分配。對於 Linux 核心來說,這兩個 Pod 中的程序具有相同的 OOM 分數,一旦核心發現記憶體不足,它就可以殺死屬於 Pod pod1
的程序。
記憶體碎片
Pod 和容器的啟動和停止序列會導致 NUMA 節點上的記憶體碎片化。記憶體管理器的 alpha 實現沒有任何機制來平衡 Pod 並整理記憶體。
記憶體管理器的未來工作
我們不想止步於記憶體管理器目前的狀況,並正在尋求改進,包括以下領域。
使記憶體管理器分配演算法更智慧
當前演算法在計算分配時忽略了 NUMA 節點之間的距離。如果無法進行同節點放置,我們仍然可以透過改變記憶體管理器來優先選擇最接近的 NUMA 節點進行跨節點分配,從而提供比當前實現更好的效能。
減少准入錯誤數量
預設的 Kubernetes 排程器不瞭解節點的 NUMA 拓撲結構,這可能是 Pod 啟動期間許多准入錯誤的原因。我們希望新增一個 KEP(Kubernetes 增強提案)來涵蓋這方面的改進。請關注 kube-scheduler 中的拓撲感知排程器外掛 以瞭解這個想法的進展。
結論
隨著記憶體管理器在 1.22 版本中晉升為 Beta 版,我們鼓勵大家嘗試一下,並期待您提出任何反饋意見。儘管仍存在一些限制,但我們已計劃了一系列增強功能來解決這些問題,並期待在即將釋出的版本中為您提供許多新功能。如果您有額外的增強功能想法或對某些功能有需求,請告訴我們。團隊始終樂於接受建議,以增強和改進記憶體管理器。我們希望您發現這篇博文內容豐富且有幫助!如果您有任何問題或意見,請告訴我們。
您可以透過以下方式聯絡我們:
- Kubernetes Slack 中的 #sig-node 頻道(如果需要邀請,請訪問 https://slack.k8s.io/)
- SIG Node 郵件列表:kubernetes-sig-node@googlegroups.com