云原生混部最后一道防線:節點水位線設計
?1.?引言
在阿里集團,在離線混部技術從 2014 年開始,經歷了七年的雙十一檢驗,內部已經大規模落地推廣,每年為阿里集團節省數十億的資源成本,整體資源利用率達到 70% 左右,達到業界領先。這兩年,我們開始把集團內的混部技術通過產品化的方式輸出給業界,通過插件化的方式無縫安裝在標準原生的k8s集群上,配合混部管控和運維能力,提升集群的資源利用率和產品的綜合用戶體驗。
由于混部是一個復雜的技術及運維體系,包括 K8s 調度、OS 隔離、可觀測性等等各種技術,之前的 2 篇文章:歷經 7 年雙 11 實戰,阿里巴巴是如何定義云原生混部調度優先級及服務質量的?如何在云原生混部場景下利用資源配額高效分配集群資源?今天我們要關注的是混部在單機運行時的最后一道防線——單機水位線設計。
2.?為什么需要單機水位線
如上圖所示,Pod 的運行時的三個生命周期階段,在經過配額檢查和調度后,終于,不同 Qos 等級的 Pod 運行在同一個節點上了,這個時候,高優和中優的 Pod 使用的是節點上的容器分配總量,而低優 Pod,則是基于高中優實際的資源用量,然后被調度器調度到節點上面去運行。從下圖可以看到,當一個節點上還有較多的空余資源時,完全可以提供給低優資源使用,而當高/中優 Pod 實際資源用量高過一定的值之后,資源競爭非常激烈時,節點上再跑低優 Pod 只會導致高/中優 Pod 的服務質量受損,所以這個時候,我們將不再允許低優 Pod 在這個節點上運行。為了標識或者說判斷節點資源的競爭激烈程度,那么非常順理成章的一個設計就是,看這個節點上的資源使用率是否過高。如果超過一定使用率,那么我們就需要對低優 Pod 做相應的操作。這個判斷的臨界閾值,就是單機的水位線。
這里另外能看到的一點是,水位線僅僅是為低優 Pod 所設置的,高/中優 Pod 并不會感知到水位線,他們可以自由地使用整機的所有資源,所有的系統行為都和沒有打開混部是一樣的。
3?.水位線的分級
對于一個資源趨向于飽和的節點來說,我們對于低優 Pod 可以有各種操作的手段,如果僅僅是簡單的殺掉低優 Pod 的話,整個混部系統也可以工作,這個動作我們稱為“驅逐”。但如果在一定時間后,機器上的資源競爭又降低的話,那么低優 Pod 被殺死并在別的機器上重新啟動,這里會大大延長低優 Pod 的單個任務的執行時間,所以在設計單機水位線時,需要盡可能的讓低優 Pod 也要在可以允許的時間范圍內能夠“降級”運行。所以,我們有對低優 Pod 的第 2 種操作,就是降低對它的 CPU 供給量,這個操作我們稱為“壓制”。同時,如果一個節點上的資源趨于飽和,另外還比較順理成章的系統行為就是不讓新的低優 Pod 被調度進來。
于是我們對于節點上低優 Pod 的行為就有 3 種:壓制、驅逐和禁止調度,由此就有三條水位線,同時,對于 CPU 這類的可壓縮資源和內存這類不可壓縮資源,行為還有區別。
注:可壓縮資源(例如 CPU 循環,disk I/O 帶寬)都是速率性的可以被回收的,對于一個 task 可以降低這些資源的量而不去殺掉 task;和不可壓縮資源(例如內存、硬盤空間)這些一般來說不殺掉 task 就沒法回收的。來自文章《在 Google 使用 Borg 進行大規模集群的管理 5-6》- 6.2 性能隔離[1]
這些水位線總體列表如下:
水位線 | 系統行為 | CPU | 內存 |
禁止調度水位線 | 不讓新的低優 Pod 被調度到這個節點上 | 有 | 有 |
壓制水位線 | 壓制低優 Pod 的資源用量 | 有 | 無 |
驅逐水位線 | 在這個節點上殺死低優 Pod,讓上層應用重新拉起新 Pod 進入重調度流程,看是否能運行在別的節點上 | 有 | 有 |
這些水位線的合理配置值,應該是 驅逐>壓制>禁止調度。不過在實際的混部生產中,我們一般會把禁止調度水位線和壓制水位線使用同一個配置值,來降低系統運維同學的理解成本,以及配置工作量。這樣合并后就會存在 CPU 的 2 條水位線,內存的一條水位線。
4?.驅逐條件:基于滿足度的驅逐模式
這張圖展示了單機上實際的系統運行例子:
- 在 t1 時間,總資源利用率達到壓制水位線的時候,對低優先級的任務進行壓制,保證整體資源利用率在壓制水位線之下,此時低優任務不會再被調度進來
- 在 t3 時間,總資源利用率開始進一步上升,達到驅逐水位線時,會對低優任務進行刪除和驅逐的處理,保證高/中優的資源使用
一個容易考慮到的設計是,驅逐低優任務前去設定一個延遲時間,這樣可以讓低優 Pod 有更多的機會等到系統有足夠的資源,繼續運行,然而這個設計,會造成幾個問題:
- 內存的驅逐必須是實時的,因為節點上內存不足,會導致高/中優任務內存不足而 OOM
- 這個延遲時間并不好配置,配的短了沒有效果,配了長了反而會引起低優 Pod 長期“饑餓”而造成低優 Pod 運行時間更長
- 如果在一個節點上,有多個低優 Pod 都在運行,是否要驅逐所有的低優 Pod?是否可能盡量的少驅逐 Pod?
因此,我們發明了基于滿足度的低優 Pod 的 CPU 資源驅逐方式,定義了以下幾個概念:
- 窗口期:獲取 CPU 利用率的時間窗口(例如 5 分鐘),在窗口時間的平均 CPU 利用率超過驅逐水位線,則開始驅逐,可以避免抖動
- 低優 Pod 資源滿足率:= 低優 Pod 實際資源使用量/低優 Pod Request 資源量
- 低優 Pod 滿足率下限:一個百分比值,低于這個值的認為低優 Pod 的資源供給不足
這樣,低優 Pod 的驅逐條件就變為了:
- 窗口期內:平均低優 Pod 資源滿足率 < 低優 Pod 滿足率下限
- 窗口期內:低優 Pod 平均 CPU 利用率接近 100%(如 90% 或者 80%)
- 當前時間:平均低優 Pod 資源滿足率 < 低優 Pod 滿足率下限
- 最近時間:BE CPU 利用率接近100%(如 90% 或者 80%)
而驅逐低優 Pod 的排序為:
- 優先驅逐調度優先級 Priority 低的 Pod(是的,即使是低優 Pod,我們還是可以按照數值來細分不同的調度優先級)
- 如果 2 個 Pod 調度優先級一致,則計算驅逐哪一個 Pod 帶來的資源釋放更多,優先驅逐能釋放更多資源的
內存的驅逐方式和 CPU 基本類似,但沒有滿足率,到了驅逐水位線按照優先級和內存大小來進行驅逐。
注:低優 Pod 的在別的節點上重建,還是依賴于低優 Pod 的管控系統(例如,離線計算的框架 Spark/Flink 等),這個重建過程往往涉及到臨時緩存的文件或者數據的遷移和一致性的校驗,這個重建操作并不適合在 K8s 層主動的去做操作,而是交給上層管控系統或者 operator 更加合適。
5.?展望:是否有更好的設計?
在本文的開始,提到了衡量系統資源的競爭激烈程度,最簡單和直觀的就是看資源利用率。當然,在實際的大規模集群運行過程中,我們也看到了資源利用率高和資源競爭激烈并不是完全的一一對應關系,甚至有些應用在 CPU 利用率非常高的情況下,依然穩定運行,而另外一些應用,在一個低的 CPU 利用情況下,就會非常的“卡”。這就意味著如果我們有新的、更好的指標來衡量系統的利用率,那么我們對相應的 Workload 就能有更“微操”的操作,在保證應用 SLO 的同時,提升集群的資源利用率。
6?.相關解決方案介紹
進入了 2022 年,混部在阿里內部已經成為了一個非常成熟的技術,為阿里每年節省數十億的成本,是阿里數據中心的基本能力。而阿里云也把這些成熟的技術經過兩年的時間,沉淀成為混部產品,開始服務于各行各業。云原生混部相關能力已經申請了多項獨立的知識產權。
在阿里云的產品族里面,我們會把混部的能力通過 ACK 敏捷版,以及 CNStack(CloudNative Stack)產品家族,對外進行透出,并結合龍蜥操作系統(OpenAnolis),形成完整的云原生數據中心混部的一體化解決方案,輸出給我們的客戶。
參考文檔:
[1]《在Google使用Borg進行大規模集群的管理 5-6》:https://my.oschina.net/HardySimpson/blog/517283?