Memory QoS 轉 Beta:v1.37 預設關閉節流
Kubernetes Blog · 2026-09-14
Kubernetes v1.37 把 MemoryQoS feature gate 從 Alpha 推進到 Beta 並且改為預設開啟,但同時把 memoryThrottlingFactor 的預設值從 0.9 改成 null,取代了先前「只要開啟 feature gate 就自動限流」的行為。這篇 2026 年 9 月 14 日刊出的官方 blog,由 Red Hat 的 Qi Wang 與 Sohan Kunkerkar 撰寫,記錄了 KEP-2570(Memory QoS)在 v1.37 的異動細節。
背景
此功能只對啟用 cgroup v2 的 Linux 節點生效,靠的是核心的 memory controller:在沒有 Memory QoS 之前,kubelet 完全不會把 Pod 的 QoS 等級告訴 cgroup,核心只能用同一套回收邏輯對待所有容器,記憶體壓力大時無法優先保護 Guaranteed 這類高保證等級的工作負載。Memory QoS 從 v1.22 起以 Alpha 形式存在,把 Pod 的 QoS 等級(Guaranteed、Burstable、BestEffort)換算成 memory.high、memory.min、memory.low 等 cgroup 參數,讓核心在記憶體壓力下有更明確的回收優先順序。問題在於 Alpha 時期的預設值不適合直接當成叢集全域預設:只要打開 MemoryQoS feature gate,memoryThrottlingFactor 就沿用內建的 0.9,kubelet 因此自動幫 Burstable 與 BestEffort 容器寫入 memory.high 限流值。v1.36 雖然加入 tiered memory reservation,讓 memoryReservationPolicy 可以做分層保留,但整體仍停在「不開則已、一開就變更行為」,沒辦法安全地把 feature gate 對所有叢集預設打開。
規格細節
v1.37 把 MemoryQoS feature gate 升為 Beta,代表每個 v1.37 的 kubelet 都會在不改任何設定的情況下自動打開這個 feature gate。為了讓「自動打開」不改變既有叢集的執行期行為,官方把 memoryThrottlingFactor 的預設值從 Alpha 的 0.9 改成 null:預設情況下 kubelet 不會再寫入任何 memory.high、memory.min、memory.low 值到 cgroup。
| 項目 | Alpha(v1.22 起) | Beta(v1.37) |
|---|---|---|
| feature gate 預設 | false,需手動加入 featureGates | true,免設定即開啟 |
| memoryThrottlingFactor 預設 | 0.9 | null(不限流) |
| 啟用後是否自動寫入 memory.high | 會 | 不會,除非手動設定 |
要拿回舊行為,得在 KubeletConfiguration 明確加回 memoryThrottlingFactor;要啟用新的分層記憶體保留,則要把 memoryReservationPolicy 設成 TieredReservation(預設是 None,不保留)。設成 TieredReservation 後,三種 QoS 等級各自對應不同的 cgroup 行為:
| Pod QoS 等級 | TieredReservation 下的 cgroup 設定 |
|---|---|
| Guaranteed | memory.min = 記憶體 limit(硬保留) |
| Burstable | memory.low = 記憶體 request(軟保留) |
| BestEffort | 不保留 |
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
memoryThrottlingFactor: 0.9
memoryReservationPolicy: TieredReservation若要在升級後完全關掉 Memory QoS,得先把設定檔調整乾淨再關 feature gate:kubelet 會拒絕 memoryThrottlingFactor 不是舊預設值 0.9、或 memoryReservationPolicy 仍是 TieredReservation 的設定檔,必須先移除或改回這兩個欄位才能設 featureGates.MemoryQoS: false。關閉後或政策不是 TieredReservation 時,kubelet 會在啟動時把殘留設定歸零:root kubepods cgroup 的 memory.min、memory.low 歸零,Burstable QoS cgroup 的 memory.low 歸零,容器層級的 memory.high 則在重啟或 resize 等 reconcile 路徑上被重設為 max。
影響範圍
已經在 kubelet 設定檔裡明確寫死 memoryThrottlingFactor 的叢集不受影響,升級後行為照舊。反而是過去靠 Alpha 內建預設值(沒在設定檔寫 memoryThrottlingFactor,單純開 feature gate 吃 0.9)的叢集,升級到 v1.37 後會悄悄停止限流——要保留舊行為,得自己把 memoryThrottlingFactor: 0.9 明確寫進 KubeletConfiguration。想要新的分層保留能力,則要主動加上 memoryReservationPolicy: TieredReservation,它不會自動生效。
官方也點名一個已知限制:memoryReservationPolicy 是整個節點層級的設定,不能針對個別 Pod 開關,一旦設成 TieredReservation,節點上每個 Guaranteed Pod 都會拿到 memory.min、每個 Burstable Pod 都會拿到 memory.low,無法讓部分 Pod 選擇退出;而硬保留的 memory.min 涵蓋整個 cgroup 記下的所有用量(包含 page cache),讀大檔案的 Pod 可能因此佔住核心原本要回收給鄰居用的記憶體。SIG Node 在 kubernetes/kubernetes#140246 追蹤這兩個問題,混跑不同保留需求工作負載的節點在升級前得先想清楚要不要開。
另外一個容易被忽略的角色是用到 Pod 原地調整資源(in-place resize)的叢集:容器層級的 memory.high 只在重啟或 resize 這類 reconcile 路徑上才會被重設為 max,代表關閉 Memory QoS 或改設定後,殘留的限流值不會立即消失,得等到下一次 resize 或容器重啟才會真的套用新設定,排查記憶體限流異常時要把這個時間差考慮進去。原文也提到 Memory QoS 的下一個里程碑是 GA,屆時的細節調整會依據 Beta 期間的回饋而定。
原始來源:Kubernetes Blog