本文已超過一年。較舊的文章可能包含過時的內容。請檢查頁面中的資訊自發布以來是否已變得不正確。

Kubernetes 記憶體管理器移至 beta 版

這篇網誌文章解釋了記憶體管理器的一些內部機制,它是 Kubernetes 1.22 的 Beta 功能。在 Kubernetes 中,記憶體管理器是 kubelet 子元件。記憶體管理器為 Guaranteed QoS 類別中的 Pod 提供保證的記憶體(和巨頁)分配。

這篇網誌文章涵蓋了

  1. 為什麼您需要它?
  2. 記憶體管理器如何運作的內部細節
  3. 記憶體管理器目前的限制
  4. 記憶體管理器的未來工作

為什麼您需要它?

一些 Kubernetes 工作負載在具有 非均勻記憶體存取 (NUMA) 的節點上執行。假設您的叢集中有 NUMA 節點。在這種情況下,您會知道當運算資源需要存取不同 NUMA 區域的記憶體時,可能會產生額外的延遲。

為了讓您的工作負載獲得最佳效能和延遲,容器 CPU、週邊設備和記憶體都應與相同的 NUMA 區域對齊。在 Kubernetes v1.22 之前,kubelet 已經提供了一組管理器來對齊 CPU 和 PCI 設備,但您沒有辦法對齊記憶體。Linux 核心能夠盡力嘗試從容器執行的相同 NUMA 節點為任務分配記憶體,但無法保證這種放置。

它是如何運作的?

記憶體管理器主要做兩件事

  • 為拓樸管理器提供拓樸提示
  • 為容器分配記憶體並更新狀態

Kubelet 下記憶體管理器的整體順序

MemoryManagerDiagram

在 Admission 階段期間

  1. 當首次處理新的 Pod 時,kubelet 會呼叫 TopologyManager 的 Admit() 方法。
  2. 拓樸管理器正在為每個提示提供者(包括記憶體管理器)呼叫 GetTopologyHints()
  3. 記憶體管理器計算 Pod 內每個容器的所有可能 NUMA 節點組合,並將提示傳回給拓樸管理器。
  4. 拓樸管理器呼叫每個提示提供者(包括記憶體管理器)的 Allocate()
  5. 記憶體管理器根據拓樸管理器選擇的提示,在狀態下分配記憶體。

在 Pod 建立期間

  1. kubelet 呼叫 PreCreateContainer()
  2. 對於每個容器,記憶體管理器會查找為容器分配記憶體的 NUMA 節點,然後將該資訊傳回給 kubelet。
  3. kubelet 透過 CRI 建立容器,使用包含來自記憶體管理器資訊的容器規格。

讓我們談談組態

預設情況下,記憶體管理器以 None 策略執行,這表示它只會放鬆而不做任何事情。若要使用記憶體管理器,您應為 kubelet 設定兩個命令列選項

  • --memory-manager-policy=Static
  • --reserved-memory="<numaNodeID>:<resourceName>=<quantity>"

--memory-manager-policy 的值很簡單:Static。決定為 --reserved-memory 指定什麼需要更多思考。若要正確組態它,您應遵循兩個主要規則

  • memory 資源的保留記憶體量必須大於零。
  • 資源類型的保留記憶體量必須等於 NodeAllocatable (kube-reserved + system-reserved + eviction-hard) 資源。您可以在 保留系統守護進程的運算資源中閱讀有關記憶體保留的更多資訊。

Reserved memory

目前的限制

1.22 版本和升級到 Beta 版帶來了增強功能和修復,但記憶體管理器仍然有一些限制。

單一與跨 NUMA 節點分配

NUMA 節點不能同時具有單一和跨 NUMA 節點分配。當容器記憶體釘選到兩個或多個 NUMA 節點時,我們無法知道容器將從哪個 NUMA 節點消耗記憶體。

Single vs Cross NUMA allocation

  1. container1 在 NUMA 節點 0 上啟動並請求 5Gi 的記憶體,但目前僅消耗 3Gi 的記憶體。
  2. 對於 container2,記憶體請求為 10Gi,並且沒有單一 NUMA 節點可以滿足它。
  3. container2 從 NUMA 節點 0 消耗 3.5Gi 的記憶體,但一旦 container1 需要更多記憶體,它將沒有記憶體,並且核心將使用 OOM 錯誤終止其中一個容器。

為了防止此類問題,記憶體管理器將拒絕 container2 的 admission,直到機器有兩個沒有單一 NUMA 節點分配的 NUMA 節點。

僅適用於 Guaranteed Pod

記憶體管理器無法保證 Burstable Pod 的記憶體分配,即使 Burstable Pod 指定了相等的記憶體限制和請求也是如此。

假設您有兩個 Burstable Pod:pod1 具有具有相等記憶體請求和限制的容器,而 pod2 僅具有設定記憶體請求的容器。您想要保證 pod1 的記憶體分配。對於 Linux 核心,任一 Pod 中的進程都具有相同的 OOM 分數,一旦核心發現它沒有足夠的記憶體,它可能會終止屬於 Pod pod1 的進程。

記憶體碎片

啟動和停止的 Pod 和容器順序可能會使 NUMA 節點上的記憶體碎片化。記憶體管理器的 Alpha 實作沒有任何機制來平衡 Pod 和整理記憶體。

記憶體管理器的未來工作

我們不想停止記憶體管理器的目前狀態,並希望進行改進,包括以下領域。

使記憶體管理器分配演算法更智慧

目前的演算法在計算分配時忽略 NUMA 節點之間的距離。如果無法進行同節點放置,透過變更記憶體管理器以優先考慮最近的 NUMA 節點進行跨節點分配,我們仍然可以提供比目前實作更好的效能。

減少 admission 錯誤的數量

預設的 Kubernetes 排程器不知道節點的 NUMA 拓樸,這可能是 Pod 啟動期間發生許多 admission 錯誤的原因。我們希望新增 KEP(Kubernetes 增強提案)以涵蓋此領域的改進。請關注 kube-scheduler 中拓樸感知排程器外掛程式,以了解此想法的進展情況。

結論

隨著記憶體管理器在 1.22 中升級到 Beta 版,我們鼓勵所有人試用它,並期待您可能提供的任何回饋。雖然仍然存在一些限制,但我們已計劃進行一系列增強功能來解決這些限制,並期待在即將發布的版本中為您提供許多新功能。如果您對其他增強功能或特定功能有任何想法,請告訴我們。團隊始終樂於接受增強和改進記憶體管理器的建議。我們希望您發現這篇網誌資訊豐富且有幫助!如果您有任何問題或意見,請告訴我們。

您可以透過以下方式聯絡我們