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

Kubernetes 資源限制案例:可預測性與效率

已經有很多文章建議不使用 Kubernetes 資源限制可能相當有用(例如,看在老天份上,停止在 Kubernetes 上使用 CPU 限制Kubernetes:透過移除 CPU 限制讓您的服務更快 )。那裡提出的觀點完全有效 – 為由於限制而不會使用的運算能力付費,或人為地增加延遲,沒有多大意義。這篇文章力求論證限制也有其合理的用途。

作為 Grafana Labs 平台團隊的網站可靠性工程師,該團隊維護和改進產品團隊使用的內部基礎架構和工具,我主要嘗試使 Kubernetes 升級盡可能順利。但我也花費大量時間深入研究各種有趣的 Kubernetes 問題。這篇文章反映了我個人的觀點,社群中的其他人可能不同意。

讓我們把問題顛倒過來。Kubernetes 叢集中的每個 Pod 都有固有的資源限制 – 它運行的機器的實際 CPU、記憶體和其他資源。如果 Pod 達到這些實體限制,它將遇到類似於達到 Kubernetes 限制時的節流。

問題

沒有(或有寬鬆的)限制的 Pod 很容易消耗節點上的額外資源。然而,這有一個隱藏的成本 – 可用的額外資源量通常很大程度上取決於排程在特定節點上的 Pod 及其真實負載。這些額外資源使每個 Pod 在實際資源分配方面都成為一個特殊的個體。更糟的是,很難弄清楚 Pod 在任何給定時刻可支配的資源 – 當然,若不進行對特定節點上運行的 Pod、其資源消耗以及類似情況的繁瑣資料挖掘,就無法得知。最後,即使我們克服了這個障礙,我們也只能獲得以一定速率採樣的資料,並僅獲得我們呼叫的一部分的設定檔。這可以擴展,但產生的可觀測性資料量可能很容易達到邊際效益遞減。因此,沒有簡單的方法可以判斷 Pod 是否有快速尖峰,並且在短時間內使用了比平常多兩倍的記憶體來處理請求突發。

現在,隨著黑色星期五和網路星期一即將到來,企業預期流量會激增。過去效能的良好效能資料/基準測試讓企業能夠規劃一些額外容量。但是關於沒有限制的 Pod 的資料是否可靠?由於額外資源處理了記憶體或 CPU 的瞬間尖峰,根據過去的資料,一切可能看起來都不錯。但是,一旦 Pod 的 bin-packing 發生變化,並且額外資源變得更加稀缺,一切都可能開始看起來不同 – 從請求延遲可以忽略不計地上升到請求緩慢滾雪球並導致 Pod OOM 終止。雖然幾乎沒有人真正關心前者,但後者是一個嚴重的問題,需要立即增加容量。

設定限制

不使用限制需要權衡 – 如果有額外資源可用,它可以機會性地提高效能,但降低了效能的可預測性,這可能會在未來反撲。有一些方法可以用於再次提高可預測性。讓我們選擇其中兩種來分析

  • 將工作負載限制設定為比請求多固定(且小)百分比 – 我稱之為固定比例的緩衝空間。這允許使用一些額外的共享資源,但保持了每個節點的超額承諾邊界,並且可以用於指導工作負載的最壞情況估計。請注意,限制百分比越大,工作負載之間可能發生的效能差異就越大。
  • 將工作負載設定為 requests = limits。從某種角度來看,這相當於為每個 Pod 提供自己的具有受限資源的小型機器;效能是相當可預測的。這也將 Pod 放入 Guaranteed QoS 類別,這使其僅在 BestEffortBurstable Pod 被節點在資源壓力下驅逐後才被驅逐(請參閱 Pod 的服務品質)。

也可以考慮其他一些情況,但這些可能是最簡單的兩種情況來討論。

叢集資源經濟性

請注意,在上面討論的兩種情況中,我們實際上都在阻止工作負載使用它擁有的某些叢集資源,代價是獲得更高的可預測性 – 這聽起來可能為了稍微更穩定的效能而付出了高昂的代價。讓我們嘗試量化那裡的影響。

Bin-packing 和叢集資源分配

首先,讓我們討論 bin-packing 和叢集資源分配。存在一些固有的叢集效率低下問題 – 很難在 Kubernetes 叢集中實現 100% 的資源分配。因此,會留下一部分未分配。

當設定固定比例的緩衝空間限制時,其中一部分將按比例提供給 Pod。如果叢集中未分配資源的百分比低於我們用於設定固定比例緩衝空間限制的常數(見圖,線 2),則所有 Pod 一起理論上能夠用完所有節點的資源;否則,將不可避免地浪費一些資源(見圖,線 1)。為了消除不可避免的資源浪費,固定比例緩衝空間限制的百分比應設定為至少等於預期的未分配資源百分比。

Chart displaying various requests/limits configurations

對於 requests = limits(見圖,線 3),情況並非如此:除非我們能夠分配所有節點的資源,否則將會有一些不可避免的資源浪費。在 requests/limits 方面沒有任何旋鈕可以調整的情況下,這裡唯一合適的方法是透過設定正確的機器設定檔來確保節點上的有效 bin-packing。這可以手動完成,也可以使用各種雲端服務供應商工具 – 例如 EKS 的 KarpenterGKE 節點自動佈建

最佳化實際資源利用率

可用資源也以其他 Pod 的未使用資源的形式出現(保留與實際 CPU 利用率等),並且它們的可用性無法以任何合理的方式預測。設定限制使得利用這些資源幾乎不可能。從不同的角度來看,如果工作負載浪費了大量它已請求的資源,則重新檢視其自身的資源請求可能是合理的。查看過去的資料並選擇更合適的資源請求可能有助於使 packing 更緊密(儘管以惡化其效能為代價 – 例如增加長尾延遲)。

結論

最佳化資源請求和限制很困難。儘管在設定限制時更容易出錯,但這些錯誤可能有助於防止稍後發生災難,因為它可以更深入地了解工作負載在邊界條件下的行為方式。在某些情況下,設定限制不太有意義:批次工作負載(對延遲不敏感 – 例如非即時視訊編碼)、盡力而為的服務(不需要那麼高的可用性並且可以被搶佔)、設計上具有大量備用資源的叢集(各種特殊工作負載的情況 – 例如設計上處理尖峰的服務)。

另一方面,設定限制並非完全不可取 ── 即使找出限制的「正確」值更加困難,而且設定錯誤的值會導致較不寬容的情況。設定限制有助於您了解工作負載在邊緣情況下的行為,而且有一些簡單的策略可以幫助您在推論正確的值時。這是在有效率的資源使用和效能可預測性之間權衡,應該這樣看待它。

對於資源使用量不穩定的工作負載,也存在經濟方面的考量。總是擁有「免費」資源並不能激勵產品團隊改進效能。夠大的峰值很容易引發效率問題,甚至在嘗試維護產品的 SLA 時產生問題 ── 因此,在評估任何風險時,這可能是一個值得一提的重點。