作者:殷達(dá)
(資料圖片)
背景
隨著 v1.8 的發(fā)布,基于 OAM 的應(yīng)用程序交付項(xiàng)目 KubeVela 已經(jīng)持續(xù)發(fā)展了 3 年多。目前已被各種組織采用并部署在生產(chǎn)環(huán)境中。無論是與托管定義一起使用還是在多個(gè)集群上進(jìn)行管理,在單個(gè) KubeVela 控制平面上運(yùn)行數(shù)千個(gè)應(yīng)用程序的情況并不少見。用戶經(jīng)常問的一個(gè)關(guān)鍵問題是 KubeVela 能否承載一定數(shù)量的應(yīng)用程序。為了回答這個(gè)問題,KubeVela 進(jìn)行了負(fù)載測(cè)試實(shí)驗(yàn),制定了性能調(diào)優(yōu)策略,并為關(guān)心 KubeVela 穩(wěn)定性和可擴(kuò)展性的用戶總結(jié)了本指南,以供各位參考。
概述
若需要尋求一個(gè)基準(zhǔn),如下簡(jiǎn)要的表格僅供參考。
盡管以上數(shù)據(jù)可能因各種因素(如應(yīng)用程序大?。┒兴煌?,但此基準(zhǔn)適用于大多數(shù)常見場(chǎng)景。
歷史
KubeVela負(fù)載測(cè)試歷史
KubeVela 過去進(jìn)行了多次負(fù)載測(cè)試:
1.2021 年 8 月對(duì)簡(jiǎn)單應(yīng)用進(jìn)行了負(fù)載測(cè)試。這次負(fù)載測(cè)試驗(yàn)證了節(jié)點(diǎn)數(shù)量不影響 KubeVela v1.0的性能。它在一個(gè)擁有 1 千個(gè)虛擬節(jié)點(diǎn)和 1.2 萬個(gè)應(yīng)用程序的單個(gè)集群上進(jìn)行了測(cè)試。這表明 Kubernetes apiserver 的速率限制是 KubeVela 核心控制器的瓶頸之一。目前為止,負(fù)載測(cè)試數(shù)據(jù)被視為標(biāo)準(zhǔn)基準(zhǔn)。參考文獻(xiàn) [1]。
它有以下幾個(gè)限制:
a.不包括在 v1.1 中發(fā)布的多集群和工作流。
b.僅測(cè)試應(yīng)用程序的創(chuàng)建和狀態(tài)保持,忽略應(yīng)用程序的持續(xù)更新。
2.*2022 年 2 月 v1.2 版本對(duì)基于工作流的應(yīng)用程序*(workflow-based application)進(jìn)行的負(fù)載測(cè)試。此次負(fù)載測(cè)試主要側(cè)重于如何在特定場(chǎng)景中微調(diào)應(yīng)用程序控制器的性能,例如不需要 ApplicationRevision 的情況。開發(fā)幾個(gè)可選的優(yōu)化標(biāo)志,并證明去掉某些功能以將性能提高 250%以上。
3.*2022 年 8 月 v1.6 版本對(duì)工作流引* 擎(workflow engine)進(jìn)行的負(fù)載測(cè)試。這次負(fù)載測(cè)試是在 KubeVela 將 cue 引擎從 v0.2 升級(jí)到 v0.4 時(shí)完成的。它主要發(fā)現(xiàn)了一些不必要的 cue 值初始化操作,這將導(dǎo)致額外的 CPU 使用成本。通過減少 75%的 CPU 使用量進(jìn)行修復(fù)。
*4.*2023 年 2 月對(duì) KubeVela v1.8 進(jìn)行的負(fù)載測(cè)試,下面將詳細(xì)介紹。本次負(fù)載測(cè)試在簡(jiǎn)單應(yīng)用程序、大型應(yīng)用程序、多個(gè)分片、多個(gè)集群、持續(xù)更新等多個(gè)場(chǎng)景下進(jìn)行。同時(shí)應(yīng)用了幾種優(yōu)化方法來處理一般情況。
全面指南
Part 01. 初期
KubeVela應(yīng)用的基本流程
KubeVela應(yīng)用的基本流程
KubeVela 應(yīng)用通常是 KubeVela 生態(tài)系統(tǒng)中最常用的對(duì)象。它由 vela-core 內(nèi)部的應(yīng)用程序控制器處理,并將使用集群網(wǎng)關(guān)進(jìn)行多集群交付。KubeVela 應(yīng)用正常處理主要流程如下:
- 用戶通過 VelaCLI、kubectl、REST API、VelaUX 等向控制平面上的 Kubernetes apiserver 發(fā)送創(chuàng)建/更新/刪除應(yīng)用程序請(qǐng)求。
- 請(qǐng)求發(fā)送到變異 Webhook 并驗(yàn)證 Webhook 以進(jìn)行驗(yàn)證和字段自動(dòng)填充。
- 存儲(chǔ)在 etcd 中的應(yīng)用程序?qū)ο?。vela-core 的 informer 接收到應(yīng)用的創(chuàng)建/更新/刪除事件,將其推送到隊(duì)列中。
- vela-core 的應(yīng)用控制器觀察事件并開始協(xié)調(diào)。
- 對(duì)于新的應(yīng)用程序,應(yīng)用程序控制器會(huì)為其打上 Finalizer。
- 控制器計(jì)算應(yīng)用程序的當(dāng)前版本并在集群中創(chuàng)建/更新它。
- 控制器執(zhí)行以工作流程為條件的工作流,運(yùn)行狀態(tài)維護(hù)和垃圾回收,最后,更新應(yīng)用程序的狀態(tài)。
應(yīng)用程序工作流主要執(zhí)行資源調(diào)度,為分析性能瓶頸并找到應(yīng)對(duì)措施,因此有必要對(duì)整個(gè)處理流程進(jìn)行概述。
如何配置高性能和魯棒的 KubeVela?
除安裝 KubeVela 之外,還有一些步驟建議用于設(shè)置高性能和魯棒的 KubeVela 控制平面。請(qǐng)注意,這些步驟對(duì)于正常使用 KubeVela 并不是強(qiáng)制的,它們主要用于大規(guī)模場(chǎng)景,比如承載 2 千多個(gè)應(yīng)用程序。
*1.*啟用可觀測(cè)性插件。要全面了解您的 KubeVela 控制平面,強(qiáng)烈建議安裝可觀測(cè)性插件,包括kube-state-metrics,prometheus-server和grafana。
a.如果您已擁有這些基礎(chǔ)設(shè)施,并且它們不是由KubeVela插件構(gòu)建的,則可以將Grafana 儀表板 [2]安裝到您的 Grafana 中,并獲取類似于 KubeVela 系統(tǒng)儀表板的內(nèi)容。
KubeVela系統(tǒng)儀表板
b.啟用這些插件需要一些額外的計(jì)算資源,如 CPU 和內(nèi)存。
*2.*刪除 Webhook。目前 KubeVela 的 Webhook 大大增加了應(yīng)用程序變更請(qǐng)求的響應(yīng)延遲。如果您已經(jīng)安裝了 KubeVela,請(qǐng)運(yùn)行kubectl delete mutatingwebhookconfiguration kubevela-vela-core-admission和kubectl delete validatingwebhookconfiguration kubevela-vela-core-admission否則,添加--set admissionWebhooks。
此步驟的負(fù)面影響包括以下幾點(diǎn):
a.無效應(yīng)用程序在創(chuàng)建或更新期間不會(huì)被拒絕。相反,它將報(bào)告應(yīng)用程序狀態(tài)中的錯(cuò)誤。
b.自動(dòng)身份驗(yàn)證將會(huì)失效。替代方案是在應(yīng)用程序應(yīng)用時(shí)為其指定身份注釋。
c.自動(dòng)分片調(diào)度將會(huì)失效。替代方案是在應(yīng)用程序應(yīng)用時(shí)為其分配預(yù)定分片 ID。
*3.*【可選】啟用 KubeVela 的多分片功能。通過使用--set sharding.enabled=true安裝,并啟用vela-core-shard-manager插件,可以運(yùn)行多個(gè)分片(從 v1.8.0開始)。通過分片,您可以對(duì)控制平面進(jìn)行橫向擴(kuò)展,且不影響任何現(xiàn)有應(yīng)用程序。
a.如果您在第 2 步中刪除了 Webhook,則需要手動(dòng)將應(yīng)用程序的標(biāo)簽controller.core.oam.dev/shard-id設(shè)置為分片 ID(默認(rèn)可以設(shè)置為 master 或 shard-0)。如果您沒有刪除 Webhook,應(yīng)用程序?qū)⒈黄骄峙洹?/p>
b.vela-core-shard-manager將使用相同的鏡像、參數(shù)等從主分片中復(fù)制配置。如果您想使用不同參數(shù),可以手動(dòng)更改。
c.如果您沒有大量的應(yīng)用程序(10k+),并且您不需要對(duì)不同的應(yīng)用程序進(jìn)行隔離(例如按租戶對(duì)他們進(jìn)行分組),則不一定需要此步驟來實(shí)現(xiàn)高性能。
KubeVela控制器分片架構(gòu)
*4.*【推薦】如果可能,請(qǐng)?jiān)诳刂破矫婧屯泄艿募褐g使用內(nèi)網(wǎng)連接。建議參考此提示,但并不總是可行的。如果您的托管集群與 KubeVela 控制平面處于不同的網(wǎng)絡(luò)區(qū)域(例如不同的地區(qū)或不同的云提供商),則無法執(zhí)行此操作。內(nèi)網(wǎng)帶寬通常比互聯(lián)網(wǎng)帶寬更高,延遲也更低。因此,使用內(nèi)網(wǎng)連接可以幫您獲得更高的吞吐量和更快的跨集群請(qǐng)求響應(yīng)速度。
如何進(jìn)行負(fù)載測(cè)試
使用KubeVela進(jìn)行負(fù)載測(cè)試的工具
在 Kubernetes 集群上設(shè)置 KubeVela 控制平面后,您可以嘗試負(fù)載測(cè)試,查看您的 KubeVela 控制平面配置是否能滿足您的業(yè)務(wù)需求。您可以根據(jù)使用場(chǎng)景從以下步驟開始。
*1.*【可選】設(shè)置 kubemark 來模擬 Kubernetes 節(jié)點(diǎn)。KubeVela 與 Kubernetes 集群的節(jié)點(diǎn)數(shù)無關(guān),但如果你想嘗試并驗(yàn)證這一點(diǎn),可以使用 kubemark 模擬 Kubernetes 節(jié)點(diǎn),這樣允許你在不實(shí)際運(yùn)行的情況下持有大量的 Pod。
a.每個(gè) kubemark pod 都會(huì)向 Kubernetes apiserver 注冊(cè)一個(gè)空節(jié)點(diǎn),并將自己注冊(cè)為一個(gè)節(jié)點(diǎn),在此節(jié)點(diǎn)上分配的 Pod 不會(huì)實(shí)際執(zhí)行,而是偽裝自己正在運(yùn)行。
b.你需要為這些空節(jié)點(diǎn)附加標(biāo)簽,并為負(fù)載測(cè)試創(chuàng)建的 Pod 設(shè)置節(jié)點(diǎn)親和性。否則,它們可能會(huì)被分配到真實(shí)節(jié)點(diǎn)并實(shí)際運(yùn)行,這將在負(fù)載測(cè)試期間產(chǎn)生巨大工作量,你應(yīng)該避免這種情況。
c.你還應(yīng)將污點(diǎn)附加到這些空節(jié)點(diǎn),并為負(fù)載測(cè)試創(chuàng)建的 Pod 添加污點(diǎn)容忍。這樣是為了防止將其他 Pod 分配到這些虛假節(jié)點(diǎn)上。例如,如果你在 Kubernetes 集群中將 Prometheus 服務(wù)器作為 Pod 運(yùn)行以構(gòu)建可觀觀測(cè)性,當(dāng)它們被分配到空節(jié)點(diǎn)時(shí),則不會(huì)實(shí)際運(yùn)行,你將一無所獲。
d.通常,一個(gè) Kubernetes 集群中的每個(gè)節(jié)點(diǎn)最多可容納數(shù)百個(gè) Pod(這個(gè)數(shù)字在不同的配置中也有所不同),因此我們建議不要在每個(gè)空節(jié)點(diǎn)上運(yùn)行太多的 Pod。20~40個(gè) Pod /節(jié)點(diǎn)可能是一個(gè)不錯(cuò)的選擇。根據(jù)你想在負(fù)載測(cè)試中測(cè)試的 Pod 數(shù)量,應(yīng)計(jì)算所需的空節(jié)點(diǎn)數(shù)。然后請(qǐng)記住,每個(gè)空節(jié)點(diǎn)都需要一個(gè)真正的 kubemark pod 來運(yùn)行,因此您需要進(jìn)一步估計(jì)運(yùn)行一定數(shù)量的 kubemark pods 需要多少個(gè)真實(shí)節(jié)點(diǎn)。
e.結(jié)論:KubeVela 對(duì)一個(gè)集群的 1 千個(gè)空節(jié)點(diǎn)進(jìn)行了負(fù)載測(cè)試,并驗(yàn)證了這個(gè)數(shù)字不會(huì)影響 KubeVela 的運(yùn)行。有關(guān)更多實(shí)驗(yàn)細(xì)節(jié),請(qǐng)參閱報(bào)告 [3]。
*2.*【可選】設(shè)置 k3d/KinD 以模擬托管集群。KubeVela 與加入到控制平面的集群數(shù)也無關(guān),除非您有超過數(shù)千個(gè) Kubernetes 集群可供使用。如果您想驗(yàn)證這個(gè)事實(shí),你可以設(shè)置 k3d 集群或 KinD 集群來模擬托管集群,并將它們加入到你的 KubeVela 控制平面。
a.托管集群使用的主要組件是 apiserver 和 etcd 。如果您不需要同時(shí)驗(yàn)證多個(gè) pod 或節(jié)點(diǎn)的數(shù)量,則只需少量資源即可運(yùn)行模擬的托管集群。就像您可以在 128 核 256 Gi 服務(wù)器上運(yùn)行 200多個(gè) k3d 集群,并將它們加入到 KubeVela 控制平面中。
b.您可以為這些已加入的集群附加標(biāo)簽,并在應(yīng)用程序交付期間測(cè)試選擇集群的性能。例如,為每 5 個(gè)集群分配一個(gè)區(qū)域 ID。
c.托管集群上不會(huì)有實(shí)際負(fù)載運(yùn)行(因?yàn)?KubeVela 主要關(guān)心應(yīng)用交付,因此在多集群負(fù)載測(cè)試期間,我們主要調(diào)度零副本部署、configmaps 和 secrets)。但網(wǎng)絡(luò)很重要,集群網(wǎng)關(guān)和托管集群的 apiserver 之間將有大量網(wǎng)絡(luò)請(qǐng)求。因此,最好確保它們之間有足夠的網(wǎng)絡(luò)帶寬和相對(duì)適中的延遲。否則,您將觀察到網(wǎng)絡(luò) IO 速率限制。
d.結(jié)論:KubeVela 還對(duì) 200個(gè)集群進(jìn)行了負(fù)載測(cè)試,這些集群被均勻分布在 40個(gè)區(qū)域。結(jié)果表明,控制平面能夠以適當(dāng)?shù)呐渲锰幚磉@些集群上的應(yīng)用程序。下面將進(jìn)一步詳細(xì)闡述。
*3.*使用腳本交付大量應(yīng)用程序。有一個(gè)關(guān)于使用官方腳本部署負(fù)載測(cè)試應(yīng)用程序的簡(jiǎn)單指南 [4]。這些腳本會(huì)自動(dòng)在多個(gè)并發(fā)線程中部署多個(gè)應(yīng)用程序。它包含多個(gè)要設(shè)置的環(huán)境變量,包括要讀取的應(yīng)用程序模板、應(yīng)用程序版本、應(yīng)用程序的分片 ID 和集群 ID 等。您可以為負(fù)載測(cè)試創(chuàng)建自己的應(yīng)用程序模板,并使用腳本進(jìn)行實(shí)驗(yàn)。KubeVela 使用該腳本測(cè)試各種示例應(yīng)用程序,并獲取負(fù)載測(cè)試統(tǒng)計(jì)數(shù)據(jù)。
Part 02. 性能優(yōu)化
在 KubeVela v1.8 中,我們添加了幾種優(yōu)化方法來提高應(yīng)用程序控制器的性能。這些方法是通過實(shí)驗(yàn)完成的。
狀態(tài)保持并行化
在 KubeVela v1.8 之前,應(yīng)用程序的狀態(tài)保持階段,應(yīng)用背后的資源是以逐一的狀態(tài)保存的。我們將并行化添加到這個(gè)過程中,最大并發(fā)數(shù)為 5 。這會(huì)將狀態(tài)保持的性能提高約 30%+,具體取決于每個(gè)應(yīng)用程序需要保留的資源數(shù)量。
優(yōu)化前后的狀態(tài)保持時(shí)間消耗
參考鏈接:
https://github.com/kubevela/kubevela/pull/5504
為列表操作索引AppKey
通過對(duì) 5 萬多個(gè)應(yīng)用程序的應(yīng)用控制器進(jìn)行 pprof 監(jiān)視,我們發(fā)現(xiàn)大部分 CPU 時(shí)間都花在列舉 ApplicationRevisions 和 ResourceTrackers 上。
KubeVela核心控制器CPU使用情況火焰圖
這是因?yàn)楫?dāng)我們需要為一個(gè)應(yīng)用程序查找這些資源時(shí),我們用標(biāo)簽選擇器選出相匹配的資源。但在控制器運(yùn)行時(shí) controller-runtime 的 informer下,這是通過匹配每個(gè)對(duì)象的標(biāo)簽來完成的。我們通過為緩存添加額外的索引來優(yōu)化它,這大大減少了列出應(yīng)用程序和資源跟蹤器所需的時(shí)間成本。對(duì)于單列表操作,時(shí)間成本從 40毫秒降至 25 微秒,這是優(yōu)化前狀態(tài)保持的一個(gè)瓶頸。
優(yōu)化前和優(yōu)化后的對(duì)賬指標(biāo)
參考鏈接:
https://github.com/kubevela/kubevela/pull/5572
過濾不必要的更新
當(dāng)一個(gè)應(yīng)用程序達(dá)到穩(wěn)定狀態(tài)(已發(fā)布且沒有進(jìn)行中的更新或刪除)時(shí),每個(gè)協(xié)調(diào)操作的主要工作是探測(cè)底層資源并檢測(cè)意外的偏移。通常,配置偏移不總是發(fā)生,因此我們不需要向底層資源發(fā)送空的補(bǔ)丁請(qǐng)求。我們觀察到這可以將協(xié)調(diào)時(shí)間縮短 20%。
應(yīng)用程序控制器和每個(gè)階段的對(duì)賬時(shí)間
此外,我們發(fā)現(xiàn)應(yīng)用程序控制器的每次協(xié)調(diào)都會(huì)發(fā)出應(yīng)用修訂更新請(qǐng)求。然而,一旦工作流成功執(zhí)行,應(yīng)用修訂就不會(huì)更新。因此,這些更新請(qǐng)求無需刪除這些請(qǐng)求就可以在負(fù)載測(cè)試期間將性能提升 27%。
優(yōu)化前(19:50之前)和優(yōu)化后應(yīng)用程序控制器的對(duì)賬時(shí)間對(duì)比
類似的問題是,從 v1.6 開始升級(jí)工作流后,狀態(tài)被壓縮,但垃圾回收的執(zhí)行沒有被去重。因此,當(dāng)刪除重復(fù)的 gc 進(jìn)程,應(yīng)用程序進(jìn)入穩(wěn)定狀態(tài)時(shí),我們進(jìn)一步實(shí)現(xiàn)了 23%的性能優(yōu)化,此時(shí)優(yōu)化了應(yīng)用程序控制器的運(yùn)行。
參考鏈接:
- https://github.com/kubevela/kubevela/pull/5598
- https://github.com/kubevela/kubevela/pull/5600
直接連接到集群網(wǎng)關(guān)
在研究將資源交付到托管集群的應(yīng)用程序時(shí),我們會(huì)發(fā)現(xiàn)集群網(wǎng)關(guān)(cluster-gateway)成了另一個(gè)潛在的瓶頸。默認(rèn)情況下,多集群請(qǐng)求是沿著 vela-core -> kubernetes apiserver (hub)-> cluster-gateway -> kubernetes apiserver (managed)的流程進(jìn)行。這是通過利用 Kubernetes 的聚合 API 機(jī)制完成的,我們可以通過允許應(yīng)用程序控制器直接與集群網(wǎng)關(guān)通信來進(jìn)行優(yōu)化。
KubeVela的多集群連接架構(gòu)
這不僅能減輕 Kubernetes apiserver 的負(fù)擔(dān),還能減少多集群請(qǐng)求的網(wǎng)絡(luò)跳數(shù)。通過這種方法我們減少了 40%的延遲。
應(yīng)用程序控制器的一個(gè)多集群請(qǐng)求延遲從11毫秒降到6毫秒
參考鏈接:
https://github.com/kubevela/kubevela/pull/5595
Informercache減少
默認(rèn)的 controller-runtime informer 將緩存我們?cè)诳刂破髦惺褂玫乃薪Y(jié)構(gòu)化對(duì)象。對(duì) KubeVela 而言,這些對(duì)象是Application,ApplicationRevision,ResourceTracker 和 ConfigMap。通過控制器分片,KubeVela 能夠?qū)pplication,ApplicationRevision 和 ResourceTracker 的緩存分成不同的分片。但隨著應(yīng)用程序的不斷更新,累積的ApplicationRevision 會(huì)通過 informer cache 占用大量?jī)?nèi)存,盡管它們并不經(jīng)常使用且內(nèi)部有大量重復(fù)數(shù)據(jù)。因此,為了優(yōu)化 informer cache 的大小,我們采取了以下幾種方法。
1.在將 managedFields 和 kubectl.kubernetes.io/last-applied-configuration 存儲(chǔ)在 informer 中時(shí),需要?jiǎng)h除 managedFields 和 kubectl.kubernetes.io/last-applied-configuration。特別是對(duì)于復(fù)雜應(yīng)用程序,它們可能會(huì)很大。它們或許對(duì)于 Kubernetes apiserver 和 CLI 工具很有用,但控制器中并不需要。因此在存儲(chǔ)到緩存之前,我們需要在控制器中將它們刪除。
2.通過共享 ComponentDefinition、TraitDefinition 和 WorkflowStepDefinition 的存儲(chǔ)空間來減少 ApplicationRevision 的內(nèi)存使用量。大多數(shù)應(yīng)用程序在系統(tǒng)中僅僅使用幾個(gè)常見定義,如 webservice 或 scaler。這些定義分別存儲(chǔ)在 ApplicationRevisions 中,并占用了大量空間。因此,在應(yīng)用程序控制器中,我們?cè)O(shè)置了一個(gè)橫向公共緩存,并讓這些 ApplicationRevisions 指向存儲(chǔ)在公共緩存中的定義,從而減少內(nèi)存使用。
KubeVela的informercache 架構(gòu)
3.禁用 ConfigMap 的 informer cache。ConfigMap 的緩存是由 Workflow Context 引起的。應(yīng)用程序工作流將運(yùn)行上下文存儲(chǔ)在 ConfigMap 中,但 ConfigMap 的緩存不僅包含工作流程使用的 ConfigMap,還包括其他未使用的 ConfigMap,這可能會(huì)占用大量空間。
優(yōu)化前后的內(nèi)存使用情況
在負(fù)載測(cè)試中,我們發(fā)現(xiàn)這些方法結(jié)合在一起對(duì)內(nèi)存使用情況進(jìn)行了重大改進(jìn),特別是對(duì)于持續(xù)更新。以前的負(fù)載測(cè)試并不重點(diǎn)關(guān)注持續(xù)更新,但這會(huì)忽略應(yīng)用程序控制器中實(shí)際使用的緩存內(nèi)存的增加。
Go 程序的內(nèi)存使用情況并不簡(jiǎn)單。上述內(nèi)存統(tǒng)計(jì)數(shù)據(jù)是操作系統(tǒng)報(bào)告的 RSS 大小。Go 程序的實(shí)際內(nèi)存使用量小于此。Go 未使用的內(nèi)存并不總是立即返回給操作系統(tǒng),并且存在內(nèi)存碎片化,這將阻止它返回所有未使用的內(nèi)存。因此,這里我們還比較了 Go 報(bào)告的 ALLOC 內(nèi)存和 SYS 內(nèi)存。ALLOC 內(nèi)存可以視為實(shí)際使用的內(nèi)存大小,SYS 內(nèi)存表示 Go 從操作系統(tǒng)獲得了多少內(nèi)存。
通過 3000 個(gè)應(yīng)用程序和 9000 個(gè)應(yīng)用程序修訂版本,我們?cè)趦?yōu)化之前得到了 1.02G 的 RSS,897M 的 SYS 和 401M 的 ALLOC。優(yōu)化后,我們得到了 739M 的 RSS ,707M 的 SYS 和 203M 的 ALLOC。可以看到使用中的內(nèi)存減少了約 50%??們?nèi)存使用情況也減少了約 25%。
參考鏈接:
https://github.com/kubevela/kubevela/pull/5683
Part 03. 實(shí)驗(yàn)
多個(gè)分片
設(shè)置
KubeVelav1.8.0支持controllersharding [5],允許 KubeVela 控制平面進(jìn)行水平擴(kuò)展。它通過利用 ListWatch 請(qǐng)求中的標(biāo)簽選擇器來實(shí)現(xiàn),controller-runtime 將其用作 KubeVela 應(yīng)用程序控制器后端。它不僅限制了每個(gè)分片要處理的應(yīng)用程序數(shù)量,還通過分割減少了內(nèi)存緩存的大小。
控制器分片的架構(gòu)
為了驗(yàn)證 KubeVela 控制器的多個(gè)分片可以按預(yù)期工作,我們比較了以下三種情況性能:
- 單個(gè)分片,使用0.5 核、1 Gi 內(nèi)存。
- 三個(gè)分片,每個(gè)分片使用0.5 核、1 Gi 內(nèi)存。
- 使用 KubeVela v1.7.5 的單個(gè)分片,使用0.5 核、1 Gi 內(nèi)存。我們?cè)趩蝹€(gè)分片情況下測(cè)試了 3000個(gè)小型應(yīng)用程序(KubeVela 核心控制器的默認(rèn)配置),在三個(gè)分片情況下測(cè)試了 9000個(gè)小型應(yīng)用程序(每個(gè)分片包含 3000個(gè)應(yīng)用程序,與單個(gè)分片情況相同)。
分析
實(shí)驗(yàn)表明,控制器分片可以橫向擴(kuò)展應(yīng)用程序容量
與單個(gè)分片的情況相比,三個(gè)分片中每個(gè)分片的資源使用量相似
我們可以看到,在使用三個(gè)分片時(shí),每個(gè)分片能夠處理 3000 個(gè) 應(yīng)用程序且不會(huì)互相干擾。在所有應(yīng)用程序發(fā)布之后,每個(gè)分片的 RSS 內(nèi)存使用量增加到 412 MiB,CPU 使用率為0.1 核(平均協(xié)調(diào)延遲為 15 毫秒)。目前,該系統(tǒng)總共包含 9000個(gè)應(yīng)用程序。與單個(gè)分片相比,分片模式下的內(nèi)存使用量和 CPU 使用量相對(duì)處于同一水平。運(yùn)行 3000 個(gè)應(yīng)用程序的單個(gè)分片,在所有發(fā)布之后使用大約0.08 核,并使用 320 MiB 的內(nèi)存。在使用分片和不使用分片之間也沒有明顯的 Reconcile 延遲差異(發(fā)布后約 40?50 毫秒,發(fā)布后為 10?15 毫秒)。
v1.8.0的性能比v1.7.5好得多
對(duì)比優(yōu)化后的單分片案例與未優(yōu)化的案例(v1.7.5),我們可以看到平均 Reconcile 時(shí)間明顯下降,特別是發(fā)布后的時(shí)間成本(從 55ms 降至 16ms)。發(fā)布后的 CPU 使用率從0.13 核降至0.08 核。內(nèi)存使用量從 676 MiB 減少到 320 MiB。
總結(jié)
綜上所述,我們通過這個(gè)實(shí)驗(yàn)得出以下結(jié)論:
- 與 v1.7.5 相比,v1.8.0 的性能有了很大的優(yōu)化。
- 部署多個(gè)分片可以橫向增加系統(tǒng)的應(yīng)用容量,并且不會(huì)引入太多的開銷。
具有持續(xù)更新的大型應(yīng)用程序
設(shè)置
雖然之前的負(fù)載測(cè)試主要集中在應(yīng)用程序的交付上,但在生產(chǎn)案例中,我們看到用戶不斷升級(jí)帶有數(shù)十個(gè)修訂版本的應(yīng)用程序。應(yīng)用程序的持續(xù)更新是否會(huì)影響控制平面的穩(wěn)定性仍然存在疑問。因此,我們進(jìn)行了這個(gè)實(shí)驗(yàn),在部署應(yīng)用程序之后進(jìn)行了幾次更新。我們發(fā)現(xiàn),在優(yōu)化之前的 v1.7.5 版本中,對(duì)應(yīng)用程序的持續(xù)更新會(huì)導(dǎo)致 KubeVela 控制器的內(nèi)存增加。這會(huì)使控制器更快地達(dá)到最大內(nèi)存使用量。例如,部署 3000 個(gè)應(yīng)用程序只用了大約 700 MiB,但將所有應(yīng)用程序更新一次會(huì)使內(nèi)存升至 900 MiB。將所有應(yīng)用程序更新兩次將導(dǎo)致控制器內(nèi)存不足并崩潰。對(duì)于 v1.6 之前的版本來說,這種情況更糟,因?yàn)槟J(rèn)的應(yīng)用程序修訂版本限制很高,并且默認(rèn)情況下系統(tǒng)中保留了大量修訂版本。解決這個(gè)問題有多方法,一種是將修訂版本限制設(shè)置為較小的數(shù)字。從 v1.7.0開始,這個(gè)數(shù)字被設(shè)置為 2,這意味著每個(gè)應(yīng)用程序最多可以保存 2 個(gè)歷史修訂版本。KubeVela 在 v1.8.0中實(shí)現(xiàn)的另一種方法是減少內(nèi)存消耗,特別是在持續(xù)更新期間增加內(nèi)存使用量。如上面的章節(jié)所示,我們可以注意到部署 3000 個(gè)輕量級(jí)應(yīng)用程序的內(nèi)存使用已大大減少。我們測(cè)試了優(yōu)化后的控制器性能,證明0.5 核 1 Gi KubeVela 控制器可以處理 3000 個(gè)大型應(yīng)用程序(每個(gè)應(yīng)用程序帶有 3 個(gè)部署、3 個(gè)密鑰和 4 個(gè)配置映射)并持續(xù)更新。在實(shí)驗(yàn)中,我們?cè)?17:11 部署了 3000 個(gè)應(yīng)用程序,并在大約 1 小時(shí)后完成了所有發(fā)布。(如果我們?cè)黾迂?fù)載測(cè)試客戶端的部署速率,可能會(huì)更快。)然后我們?cè)?19:05、20:05、20:55、22:00、23:27 更新了所有的應(yīng)用程序。請(qǐng)注意,每個(gè)應(yīng)用程序的歷史修訂版本數(shù)量的默認(rèn)設(shè)置為 2 。因此,在前兩次更新中,會(huì)生成新的應(yīng)用程序修訂版本,而在接下來的三次更新中,會(huì)創(chuàng)建新的修訂版本并回收過時(shí)的修訂版本。
分析
應(yīng)用程序更新比應(yīng)用程序創(chuàng)建慢
應(yīng)用程序的更新比部署需要更多的時(shí)間,因?yàn)閼?yīng)用程序還需要處理過時(shí)資源的垃圾回收。因此,我們觀察到控制器隊(duì)列的增加,但這并會(huì)不持續(xù)很長(zhǎng)時(shí)間。應(yīng)用程序的平均工作流完成時(shí)間仍然保持在 1 分鐘以下。
在更新過程中 CPU 使用率很高,成為瓶頸。內(nèi)存僅在前兩次更新時(shí)增加
(受 ApplicationRevision 的限制)
當(dāng)我們查看 KubeVela 控制器的資源使用情況時(shí),我們注意到在更新過程中,CPU 使用率已達(dá)到0.5 核,這是使控制器工作變慢的主要原因之一??刂破髦挥性趹?yīng)用部署和狀態(tài)保持資源時(shí)才支持并行執(zhí)行,但目前不支持并行垃圾回收(我們希望在未來添加)??刂破鞯膬?nèi)存使用量在第一次發(fā)布后達(dá)到了 470 MiB。在前兩次更新后,它上升到 580 MiB 和 654 MiB 。然后對(duì)于以下更新,它保持在690 MiB 左右(低于內(nèi)存限制的 70%),并且沒有進(jìn)一步連續(xù)增加。Go 的內(nèi)存分配機(jī)制不會(huì)立即將未使用的內(nèi)存返回給操作系統(tǒng),也不是所有未使用的內(nèi)存總是可以被返回。因此,內(nèi)存的實(shí)際使用量(分配的內(nèi)存)通常遠(yuǎn)低于常駐集大小。當(dāng) KubeVela 控制器的隊(duì)列中有很高的負(fù)載和積累時(shí),內(nèi)存使用量可能會(huì)一度很高,但不會(huì)持續(xù)下去。有些人可能會(huì)問,這樣的應(yīng)用程序模板真的足夠大?的確,我們已經(jīng)看到有用戶在一個(gè)應(yīng)用程序中調(diào)度了 50多個(gè) Kubernetes 資源,這至少比我們?cè)谶@里測(cè)試的應(yīng)用程序的 5 倍。但平均而言,龐大的應(yīng)用程序只是整個(gè)系統(tǒng)的一小部分,并且這里的測(cè)試將所有應(yīng)用程序設(shè)置為相同的大小。此外,如果我們將這個(gè)實(shí)驗(yàn)與上一節(jié)中的測(cè)試(多分片中的單個(gè)分片案例)進(jìn)行比較,其中,我們對(duì) 3000 個(gè)小應(yīng)用程序(3 個(gè)資源)使用了相同的控制器配置,我們可以發(fā)現(xiàn)在這個(gè)實(shí)驗(yàn)中使用的應(yīng)用程序大了 3 倍以上,但控制器的性能僅略有下降。
總結(jié)
總之,我們從實(shí)驗(yàn)中得知以下幾點(diǎn):
- 在標(biāo)準(zhǔn)控制器設(shè)置下,KubeVela 控制器能夠容納 3000 個(gè)大型應(yīng)用程序并對(duì)其進(jìn)行持續(xù)更新。
- 應(yīng)用程序的更新速度比創(chuàng)建速度慢,它會(huì)消耗更多的計(jì)算資源。
- 與小型應(yīng)用程序相比,大型應(yīng)用程序?qū)?KubeVela 控制器的性能影響不大。
多集群
設(shè)置
上述負(fù)載測(cè)試和 KubeVela 在歷史上所做的所有負(fù)載測(cè)試都使用單集群架構(gòu)來部署和管理應(yīng)用程序。隨著越來越多的用戶開始在多個(gè)集群中管理應(yīng)用程序,我們想要了解 KubeVela 在多集群場(chǎng)景下的表現(xiàn)。因此,我們?cè)O(shè)計(jì)了這個(gè)實(shí)驗(yàn)。在這個(gè)實(shí)驗(yàn)中,我們也使用了 KubeVela 控制器的默認(rèn)配置,0.5 核 1 Gi,并使用 v1.8.0中的集群網(wǎng)關(guān)的默認(rèn)配置(0.5 核 200 MiB)。除了將這些資源部署到遠(yuǎn)程集群之外,我們還使用了小型應(yīng)用程序模板(1 個(gè)部署,1 個(gè)配置映射和 1 個(gè)密鑰)。我們進(jìn)行這個(gè)實(shí)驗(yàn)是為了測(cè)試跨地區(qū)的性能。KubeVela 的控制平面部署在日本東京,而托管集群則部署在中國杭州。我們還比較了 v1.8.0和 v1.7.5 的性能。v1.7.5 的集群網(wǎng)關(guān)默認(rèn)配置使用0.1 核 200 MiB,因此為了進(jìn)行公平比較,我們將其改進(jìn)為 v1.8.0中給出的資源。
分析
v1.7.5和v1.8.0都可以處理3k個(gè)多集群應(yīng)用程序,但v1.8.0的性能更好
v1.8.0控制器發(fā)送請(qǐng)求更少且速度更快
我們發(fā)現(xiàn),在這兩個(gè)版本中,KubeVela 都能夠在遠(yuǎn)程集群中處理 3000 個(gè)應(yīng)用程序和管理資源,但 KubeVela v1.8.0的性能優(yōu)于 v1.7.5,這要?dú)w功于我們上面提到的優(yōu)化。我們發(fā)現(xiàn) v1.7.5 的控制器隊(duì)列保持在高狀態(tài),這是由于較長(zhǎng)的協(xié)調(diào)時(shí)間引起的,這可能會(huì)使控制器對(duì)應(yīng)用程序突變的響應(yīng)變慢。除了針對(duì)集群網(wǎng)關(guān)的優(yōu)化外,所有其他針對(duì)單個(gè)集群情況的優(yōu)化技巧在多集群情況下也同樣適用。
多集群請(qǐng)求比單個(gè)集群請(qǐng)求慢得多,主要由控制平面和托管集群間的延遲引起
與單集群情況下的 3000 個(gè)小型應(yīng)用程序相比,在遠(yuǎn)程集群中部署資源可能會(huì)大大增加 KubeVela 控制器的時(shí)間成本。從儀表盤中可以看出,控制器的請(qǐng)求延遲平均約為 77 毫秒(單集群情況下為 20毫秒),而集群網(wǎng)關(guān)的延遲平均約為 72 毫秒,與集群間延遲相比開銷很小。
CPU使用率和內(nèi)存使用率沒有差異
盡管延遲比單集群情況更大,但如果我們看 KubeVela 控制器的計(jì)算資源使用情況,會(huì)發(fā)現(xiàn) CPU 使用率和內(nèi)存使用率并沒有太大的差異。
總結(jié)
從這個(gè)實(shí)驗(yàn)我們一般可以了解到以下幾點(diǎn):
1.在多集群場(chǎng)景下,v1.8.0 KubeVela 的性能表現(xiàn)比 v1.7.5 好。
2.在多集群場(chǎng)景下,KubeVela 控制器的內(nèi)存消耗接近單集群情況。
3.KubeVela v1.8.0 能夠默認(rèn)處理包括單集群、大型應(yīng)用程序、多集群部署、持續(xù)更新在內(nèi)的 3k 個(gè)應(yīng)用程序。
4.如果托管集群與控制平面之間的延遲較大,則 KubeVela 控制器的性能將會(huì)更差。
優(yōu)化方法:
a.通過增加 CPU、并發(fā)和 QPS/Burst,提高 KubeVela 控制器的并行性。
b.減少跨集群的延遲。(檢查網(wǎng)絡(luò)帶寬并確保沒有速率限制)
大規(guī)模
設(shè)置
在測(cè)試了多集群和多個(gè)分片之后,我們現(xiàn)在知道 KubeVela 有能力處理跨集群的大量應(yīng)用程序。我們?cè)O(shè)計(jì)了一個(gè)大規(guī)模的負(fù)載測(cè)試,以驗(yàn)證通過適當(dāng)?shù)呐渲?,單個(gè) KubeVela 控制平面可以滿足管理海量集群的需要。我們通過 k3d 在 64 核 256 Gi 虛擬機(jī)(阿里云上的 ECS)上模擬了 200個(gè)托管集群。對(duì)于控制平面,我們使用了大型 ACK 集群(阿里云上的 Kubernetes),其中有 8 個(gè)( 3 個(gè)主節(jié)點(diǎn)和 5 個(gè)工作節(jié)點(diǎn))32 核 128 Gi 節(jié)點(diǎn)。我們運(yùn)行了 5 個(gè)分片控制器,每個(gè)分片控制器都有 8 核 32 Gi,32 個(gè)并發(fā)協(xié)調(diào)器,4000 QPS 6000 Burst。我們又運(yùn)行了另外 5 個(gè)集群網(wǎng)關(guān),每個(gè)都有 2 核 1 Gi。請(qǐng)注意,我們?cè)试S托管集群位于在同一個(gè) VPC 中,并使用內(nèi)網(wǎng)連接。這將減少控制平面和托管集群之間的延遲,并增加最大網(wǎng)絡(luò)吞吐量。我們向系統(tǒng)部署了 40 萬個(gè)小型應(yīng)用程序。它們的資源被平均分配到了 200個(gè)集群中。
控制平面上運(yùn)行的應(yīng)用程序和控制器數(shù)量
分析
這 40萬個(gè)應(yīng)用程序的交付分為了幾個(gè)階段。首先,我們部署了 2 萬個(gè)應(yīng)用程序,以查看是否一切正常,并檢查是否存在任何潛在瓶頸。其次,我們部署了另外 18 萬個(gè)應(yīng)用程序,以查看系統(tǒng)是否能夠承載 20 萬個(gè)應(yīng)用程序。最后,我們將數(shù)量增加到 40 萬。
隨著多集群請(qǐng)求延遲增加,控制器表現(xiàn)不佳。
通過向集群網(wǎng)關(guān)添加更多 CPU 并消除 pod 間不平衡的工作負(fù)載來解決
當(dāng)我們部署了 20萬個(gè)應(yīng)用程序時(shí),控制器的性能開始下降,你會(huì)發(fā)現(xiàn)在大約 2:00時(shí),控制器隊(duì)列開始上升,平均調(diào)和時(shí)間大大增加。這是由 KubeVela 控制器的一個(gè)分片重新啟動(dòng)引起的,需要進(jìn)一步調(diào)查??刂破鞅旧淼闹貑⒉]有影響應(yīng)用程序的運(yùn)行,但后來我們發(fā)現(xiàn) cluster-gateway pod 的負(fù)載沒有均衡分布。大量負(fù)載集中在兩個(gè) cluster-gateway pod 上,導(dǎo)致它們的 CPU 使用率達(dá)到 90%以上。這大大降低了多集群請(qǐng)求的吞吐量,導(dǎo)致應(yīng)用程序協(xié)調(diào)緩慢。大約在 10:00,我們注意到了該異常,并重新啟動(dòng)集群網(wǎng)關(guān) pod 以提高它們的 CPU(4 核1 Gi * 5),這解決了暴露的瓶頸。后來我們又添加了另外 20萬個(gè)應(yīng)用程序,響應(yīng)延遲始終很低。發(fā)布了 40 萬個(gè)應(yīng)用程序后,平均調(diào)和時(shí)間(reconciliation time)為 70 毫秒,但在不同的分片間有所不同。一些分片具有較低的多集群請(qǐng)求延遲,例如每個(gè)請(qǐng)求 15 毫秒,而其他分片的延遲更高,可達(dá) 30 毫秒。原因還于集群網(wǎng)關(guān)的多個(gè)副本之間負(fù)載不平衡。但總的來說,如果您只有一個(gè) cluster-gateway 副本,您將不會(huì)遇到此問題。
由于中心控制平面與托管集群之間的集群網(wǎng)關(guān)直接通過內(nèi)網(wǎng)連接,多集群請(qǐng)求與控制平面內(nèi)請(qǐng)求具有相似的延遲
同時(shí)值得注意的是,在這種大規(guī)模實(shí)驗(yàn)中,管理集群和控制平面彼此靠近,它們之間的流量傳輸也非??臁R虼?,與上面的多集群實(shí)驗(yàn)不同,我們可以保持與單集群情況相似的的低調(diào)諧時(shí)間(reconciliation time)。
隨著應(yīng)用數(shù)量的增加,內(nèi)存和CPU的使用率增長(zhǎng)的速度比應(yīng)用數(shù)量的增長(zhǎng)慢得多
40萬個(gè)應(yīng)用程序并不是 KubeVela 控制平面可容納的最大數(shù)量。每個(gè)控制器分片只使用了不到 20%的 32 Gi 內(nèi)存,CPU 使用率也遠(yuǎn)未滿負(fù)荷。但由于在 hub Kubernetes 的 etcd 中存儲(chǔ)了大量對(duì)象(Application、ResourceTracker、ApplicationRevision),因此 hub kube-apiserver 和其他原生組件(如 kube-controller-manager)開始使用大量計(jì)算資源,例如超過 90 Gi 的內(nèi)存。系統(tǒng)的瓶頸逐漸落到 Kubernetes 本身。
為了進(jìn)一步驗(yàn)證上述假設(shè),我們將 KubeVela 控制器的內(nèi)存從每個(gè)分片 8 個(gè)核 32 Gi 縮減到每個(gè)分片的 8 核 16 Gi(總共 5 個(gè)分片),并使用一個(gè)具有 16 核 4 Gi 的單個(gè)集群網(wǎng)關(guān)副本來消除工作負(fù)載的不平衡。我們將應(yīng)用程序的數(shù)量增加到 50 萬,發(fā)現(xiàn)所有分片都具有相似的性能。所有控制器分片的 CPU 和內(nèi)存使用率均正常??刂破鞣制墓ぷ麝?duì)列為空,狀態(tài)保留的平均協(xié)調(diào)時(shí)間平均約為 60毫秒。群集網(wǎng)關(guān) Pod 的負(fù)載較高,但可以將多集群請(qǐng)求的平均延遲保持在較低水平(23 毫秒)。
調(diào)整后所有分片的資源使用情況相似
當(dāng)我們將應(yīng)用程序數(shù)量從40萬增加到50萬時(shí),發(fā)現(xiàn)對(duì)賬時(shí)間沒有顯著增加
我們認(rèn)為,40 萬/50 萬個(gè)應(yīng)用程序的數(shù)量對(duì)于幾乎所有的 KubeVela 用戶已經(jīng)足夠大了,因此我們?cè)谶@里停止了實(shí)驗(yàn)。
總結(jié)
總之,這個(gè)大規(guī)模實(shí)驗(yàn)表明,在特定條件下,KubeVela 控制平面具有擴(kuò)展和容納極大量應(yīng)用程序的能力。
總結(jié)
通過一系列在不同場(chǎng)景下的實(shí)驗(yàn),KubeVela v1.8.0展示了其穩(wěn)定性和可擴(kuò)展性。與 v1.7.5 相比,其性能有相當(dāng)大的提升,這為系統(tǒng)運(yùn)維人員有信心讓 KubeVela 管理大規(guī)模應(yīng)用平臺(tái)?,F(xiàn)在,KubeVela 已經(jīng)發(fā)展成為構(gòu)建應(yīng)用平臺(tái)的綜合解決方案。雖然進(jìn)行的負(fù)載測(cè)試覆蓋了 KubeVela 一些最流行的用例,但我們也看到了 KubeVela 許多更高級(jí)的用法,比如輸入/輸出復(fù)雜工作流、金絲雀發(fā)布、GitOps 等。根據(jù)用戶使用 KubeVela 的方式,KubeVela 系統(tǒng)的性能可能會(huì)暴露出不同的瓶頸。我們總結(jié)了一些微不足道的解決方案,如下所示。
診斷系統(tǒng)性能瓶頸及解決方法
有時(shí),整個(gè)應(yīng)用系統(tǒng)的瓶頸并不是 KubeVela 本身。例如,如果托管集群的響應(yīng)速度緩慢或吞吐量有限,我們可以提高 KubeVela 控制器的吞吐量,但控制器本身無法減少延遲。由于插件帶來的系統(tǒng)可觀測(cè)性,在大多數(shù)情況下,您可以在儀表板上找到系統(tǒng)性能不佳的一些線索,并應(yīng)用適當(dāng)?shù)牟呗赃M(jìn)行優(yōu)化。未來,KubeVela 會(huì)持續(xù)關(guān)注整個(gè)系統(tǒng)的底層性能,并確保它始終能夠?yàn)閼?yīng)用程序交付提供穩(wěn)定、快速的功能。
您可以通過如下材料了解更多關(guān)于 KubeVela 以及 OAM 項(xiàng)目的細(xì)節(jié):
- 項(xiàng)目代碼庫:https://github.com/kubevela/kubevela歡迎 Star/Watch/Fork!
- 項(xiàng)目官方主頁與文檔:kubevela.io,從 1.1 版本開始,已提供中文、英文文檔,更多語言文檔歡迎開發(fā)者進(jìn)行翻譯。
- 項(xiàng)目釘釘群:23310022;Slack:CNCF #kubevela Channel
相關(guān)鏈接:
CNCF 官網(wǎng)的英文博客原文地址:https://www.cncf.io/blog/2023/04/12/stability-and-scalability-assessment-of-kubevela/
[1]參考文獻(xiàn)
https://kubevela.net/blog/2021/08/30/kubevela-performance-test
[2]Grafana 儀表板
https://grafana.com/grafana/dashboards/18200-kubevela-system/
[3]報(bào)告
https://kubevela.net/blog/2021/08/30/kubevela-performance-test
[4]指南
https://github.com/kubevela/kubevela/tree/master/hack/load-test#use-of-application-bulk-deploy-scripts
[5]controllersharding
https://kubevela.net/docs/platform-engineers/system-operation/controller-sharding
點(diǎn)擊此處查看KubeVela項(xiàng)目官網(wǎng)
關(guān)鍵詞: