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

記憶體資源的服務品質

於 2021 年 8 月發布的 Kubernetes v1.22 推出了一項新的 Alpha 功能,改善了 Linux 節點實作記憶體資源請求和限制的方式。

在先前的版本中,Kubernetes 不支援記憶體品質保證。例如,如果您將容器資源設定如下

apiVersion: v1
kind: Pod
metadata:
  name: example
spec:
  containers:
  - name: nginx
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "64Mi"
        cpu: "500m"

spec.containers[].resources.requests(例如 cpu、記憶體)是為排程而設計的。當您建立 Pod 時,Kubernetes 排程器會選擇一個節點來執行 Pod。每個節點對於每種資源類型都有最大容量:它可以為 Pod 提供的 CPU 和記憶體量。排程器確保對於每種資源類型,排程容器的資源請求總和都小於節點的容量。

當 kubelet 啟動容器時,spec.containers[].resources.limits 會傳遞至容器執行階段。CPU 被視為「可壓縮」資源。如果您的應用程式開始達到 CPU 限制,Kubernetes 會開始節流您的容器,導致您的應用程式效能可能更差。但是,它不會被終止。這就是「可壓縮」的意思。

在 cgroup v1 中,以及在此功能之前,容器執行階段從未考慮且實際上忽略了 spec.containers[].resources.requests["memory"]。這與 CPU 不同,在 CPU 中,容器執行階段會同時考慮請求和限制。此外,記憶體實際上無法在 cgroup v1 中壓縮。由於沒有辦法節流記憶體使用量,如果容器超過其記憶體限制,核心會終止它並發出 OOM(記憶體不足)終止訊號。

幸運的是,cgroup v2 帶來了新的設計和實作,以實現對記憶體的全面保護。新功能依賴 cgroups v2,而大多數目前 Linux 作業系統版本都已提供 cgroups v2。透過這項實驗性功能,Pod 和容器的服務品質不僅涵蓋 CPU 時間,還涵蓋記憶體。

它是如何運作的?

Memory QoS 使用 cgroup v2 的記憶體控制器來保證 Kubernetes 中的記憶體資源。Pod 中容器的記憶體請求和限制用於設定記憶體控制器提供的特定介面 `memory.min` 和 `memory.high`。當 `memory.min` 設定為記憶體請求時,記憶體資源會被保留且永遠不會被核心回收;這就是 Memory QoS 如何確保 Kubernetes Pod 的記憶體可用性的方式。如果容器中設定了記憶體限制,則表示系統需要限制容器記憶體使用量,Memory QoS 會使用 `memory.high` 來節流接近記憶體限制的工作負載,確保系統不會被瞬間的記憶體配置壓垮。

下表詳細說明了這兩個參數的特定功能,以及它們如何對應到 Kubernetes 容器資源。

檔案描述
memory.min`memory.min` 指定 cgroup 必須始終保留的最小記憶體量,即永遠無法被系統回收的記憶體。如果 cgroup 的記憶體使用量達到此下限且無法增加,則系統會調用 OOM killer。

我們將其映射到容器的記憶體請求
memory.high`memory.high` 是記憶體使用量節流限制。這是控制 cgroup 記憶體使用的主要機制。如果 cgroup 的記憶體使用量超過此處指定的高邊界,則 cgroup 的進程會被節流並置於繁重的回收壓力之下。預設值為 max,表示沒有限制。

我們使用一個公式來計算 `memory.high`,具體取決於容器的記憶體限制或節點可分配記憶體(如果容器的記憶體限制為空)和節流因子。有關公式的更多詳細資訊,請參閱 KEP。

當發出容器記憶體請求時,kubelet 會在容器建立期間透過 CRI 中的 `Unified` 欄位將 `memory.min` 傳遞到後端 CRI 執行階段(可能是 containerd、cri-o)。容器層級 cgroup 中的 `memory.min` 將設定為


i:一個 Pod 中的第 i 個容器

由於 `memory.min` 介面要求所有祖先 cgroup 目錄都已設定,因此需要正確設定 Pod 和節點 cgroup 目錄。

Pod 層級 cgroup 中的 `memory.min`

i:一個 Pod 中的第 i 個容器

節點層級 cgroup 中的 `memory.min`

i:一個節點中的第 i 個 Pod,j:一個 Pod 中的第 j 個容器

Kubelet 將使用 runc libcontainer 程式庫直接管理 Pod 層級和節點層級 cgroup 的 cgroup 層次結構,而容器 cgroup 限制由容器執行階段管理。

對於記憶體限制,除了限制記憶體使用量的原始方式之外,Memory QoS 還增加了一項節流記憶體分配的額外功能。引入了一個節流因子作為乘數(預設值為 0.8)。如果將記憶體限制乘以因子的結果大於記憶體請求,則 kubelet 會將 `memory.high` 設定為該值並透過 CRI 使用 `Unified`。如果容器未指定記憶體限制,則 kubelet 將改為使用節點可分配記憶體。容器層級 cgroup 中的 `memory.high` 設定為


i:一個 Pod 中的第 i 個容器

這可以幫助在 Pod 記憶體使用量增加時提高穩定性,確保在記憶體接近記憶體限制時對其進行節流。

我該如何使用它?

以下是在您的 Linux 節點上啟用 Memory QoS 的先決條件,其中一些與 Kubernetes 對 cgroup v2 的支援有關。

  1. Kubernetes v1.22 及更高版本
  2. runc v1.0.0-rc93 及更高版本;containerd 1.4 及更高版本;cri-o 1.20 及更高版本
  3. Linux 核心最低版本:4.15,建議版本:5.2+
  4. 已啟用 cgroupv2 的 Linux 映像檔,或手動啟用 cgroupv2 unified_cgroup_hierarchy

OCI 執行階段(例如 runc 和 crun)已支援 cgroups v2 `Unified`,而 Kubernetes CRI 也已進行所需的變更以支援傳遞 `Unified`。但是,也需要 CRI 執行階段支援。Alpha 階段的 Memory QoS 旨在支援 containerd 和 cri-o。相關的 PR Feature: containerd-cri support LinuxContainerResources.Unified #5627 已合併,將在 containerd 1.6 中發布。CRI-O implement kube alpha features for 1.22 #5207 仍在 WIP 中。

滿足這些先決條件後,您可以啟用記憶體 QoS 功能閘道(請參閱透過組態檔設定 kubelet 參數)。

我該如何了解更多資訊?

您可以找到更多詳細資訊如下

我該如何參與?

您可以透過幾種方式聯繫 SIG Node

您也可以直接聯繫我