作者 | 阿里云容器平臺(tái)高級(jí)技術(shù)專家 曾凡松(逐靈)
創(chuàng)新互聯(lián)專注于企業(yè)成都全網(wǎng)營(yíng)銷、網(wǎng)站重做改版、長(zhǎng)垣網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、H5開發(fā)、商城系統(tǒng)網(wǎng)站開發(fā)、集團(tuán)公司官網(wǎng)建設(shè)、外貿(mào)網(wǎng)站建設(shè)、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性價(jià)比高,為長(zhǎng)垣等各大城市提供網(wǎng)站開發(fā)制作服務(wù)。本文主要介紹阿里巴巴在大規(guī)模生產(chǎn)環(huán)境中落地 Kubernetes 的過程中,在集群規(guī)模上遇到的典型問題以及對(duì)應(yīng)的解決方案,內(nèi)容包含對(duì) etcd、kube-apiserver、kube-controller 的若干性能及穩(wěn)定性增強(qiáng),這些關(guān)鍵的增強(qiáng)是阿里巴巴內(nèi)部上萬節(jié)點(diǎn)的 Kubernetes 集群能夠平穩(wěn)支撐?2019 年天貓 618 大促的關(guān)鍵所在。
從阿里巴巴最早期的 AI 系統(tǒng)(2013)開始,集群管理系統(tǒng)經(jīng)歷了多輪的架構(gòu)演進(jìn),到 2018 年全面的應(yīng)用 Kubernetes ,這期間的故事是非常精彩的,有機(jī)會(huì)可以單獨(dú)給大家做一個(gè)分享。這里忽略系統(tǒng)演進(jìn)的過程,不去討論為什么 Kubernetes 能夠在社區(qū)和公司內(nèi)部全面的勝出,而是將焦點(diǎn)關(guān)注到應(yīng)用 Kubernetes 中會(huì)遇到什么樣的問題,以及我們做了哪些關(guān)鍵的優(yōu)化。
在阿里巴巴的生產(chǎn)環(huán)境中,容器化的應(yīng)用超過了 10k 個(gè),全網(wǎng)的容器在百萬的級(jí)別,運(yùn)行在十幾萬臺(tái)宿主機(jī)上。支撐阿里巴巴核心電商業(yè)務(wù)的集群有十幾個(gè),大的集群有幾萬的節(jié)點(diǎn)。在落地 Kubernetes 的過程中,在規(guī)模上面臨了很大的挑戰(zhàn),比如如何將 Kubernetes 應(yīng)用到超大規(guī)模的生產(chǎn)級(jí)別。
羅馬不是一天就建成的,為了了解 Kubernetes 的性能瓶頸,我們結(jié)合阿里的生產(chǎn)集群現(xiàn)狀,估算了在 10k 個(gè)節(jié)點(diǎn)的集群中,預(yù)計(jì)會(huì)達(dá)到的規(guī)模:
我們基于 Kubemark 搭建了大規(guī)模集群模擬的平臺(tái),通過一個(gè)容器啟動(dòng)多個(gè)(50個(gè))Kubemark 進(jìn)程的方式,使用了 200 個(gè) 4c 的容器模擬了 10k 節(jié)點(diǎn)的 kubelet。在模擬集群中運(yùn)行常見的負(fù)載時(shí),我們發(fā)現(xiàn)一些基本的操作比如 Pod 調(diào)度延遲非常高,達(dá)到了驚人的 10s 這一級(jí)別,并且集群處在非常不穩(wěn)定的狀態(tài)。
當(dāng) Kubernetes 集群規(guī)模達(dá)到 10k 節(jié)點(diǎn)時(shí),系統(tǒng)的各個(gè)組件均出現(xiàn)相應(yīng)的性能問題,比如:
為了解決這些問題,阿里云容器平臺(tái)在各方面都做了很大的努力,改進(jìn) Kubernetes 在大規(guī)模場(chǎng)景下的性能。
首先是 etcd 層面,作為 Kubernetes 存儲(chǔ)對(duì)象的數(shù)據(jù)庫,其對(duì) Kubernetes 集群的性能影響至關(guān)重要。
第一版本的改進(jìn),我們通過將 etcd 的數(shù)據(jù)轉(zhuǎn)存到 tair 集群中,提高了 etcd 存儲(chǔ)的數(shù)據(jù)總量。但這個(gè)方式有一個(gè)顯著的弊端是額外增加的 tair 集群,增加的運(yùn)維復(fù)雜性對(duì)集群中的數(shù)據(jù)安全性帶來了很大的挑戰(zhàn),同時(shí)其數(shù)據(jù)一致性模型也并非基于 raft 復(fù)制組,犧牲了數(shù)據(jù)的安全性。
第二版本的改進(jìn),我們通過將 API Server 中不同類型的對(duì)象存儲(chǔ)到不同的 etcd 集群中。從 etcd 內(nèi)部看,也就對(duì)應(yīng)了不同的數(shù)據(jù)目錄,通過將不同目錄的數(shù)據(jù)路由到不同的后端 etcd 中,從而降低了單個(gè) etcd 集群中存儲(chǔ)的數(shù)據(jù)總量,提高了擴(kuò)展性。
為了解決該問題,我們?cè)O(shè)計(jì)了基于 segregrated hashmap 的空閑頁面管理算法,hashmap 以連續(xù) page 大小為 key, 連續(xù)頁面起始 page id 為? value。通過查這個(gè) segregrated hashmap?實(shí)現(xiàn) O(1) 的空閑 page 查找,極大地提高了性能。在釋放塊時(shí),新算法嘗試和地址相鄰的 page 合并,并更新 segregrated hashmap。更詳細(xì)的算法分析可以見已發(fā)表在 CNCF 博客的博文:
https://www.cncf.io/blog/2019/05/09/performance-optimization-of-etcd-in-web-scale-data-scenario/
通過這個(gè)算法改進(jìn),我們可以將 etcd 的存儲(chǔ)空間從推薦的 2GB 擴(kuò)展到 100GB,極大的提高了 etcd 存儲(chǔ)數(shù)據(jù)的規(guī)模,并且讀寫無顯著延遲增長(zhǎng)。除此之外,我們也和谷歌工程師協(xié)作開發(fā)了 etcd raft learner(類 zookeeper observer)/fully concurrent read 等特性,在數(shù)據(jù)的安全性和讀寫性能上進(jìn)行增強(qiáng)。這些改進(jìn)已貢獻(xiàn)開源,將在社區(qū) etcd 3.4 版本中發(fā)布。
在 Kubernetes 集群中,影響其擴(kuò)展到更大規(guī)模的一個(gè)核心問題是如何有效的處理節(jié)點(diǎn)的心跳。在一個(gè)典型的生產(chǎn)環(huán)境中 (non-trival),kubelet 每 10s 匯報(bào)一次心跳,每次心跳請(qǐng)求的內(nèi)容達(dá)到 15kb(包含節(jié)點(diǎn)上數(shù)十計(jì)的鏡像,和若干的卷信息),這會(huì)帶來兩大問題:
為了解決這個(gè)問題,Kubernetes 引入了一個(gè)新的 build-in Lease API
?,將與心跳密切相關(guān)的信息從 node 對(duì)象中剝離出來,也就是上圖中的 Lease
?。原本 kubelet 每 10s 更新一次 node 對(duì)象升級(jí)為:
因?yàn)?Lease
?對(duì)象非常小,因此其更新的代價(jià)遠(yuǎn)小于更新 node 對(duì)象。kubernetes 通過這個(gè)機(jī)制,顯著的降低了 API Server 的 CPU 開銷,同時(shí)也大幅減小了 etcd 中大量的 transaction logs,成功將其規(guī)模從 1000 擴(kuò)展到了幾千個(gè)節(jié)點(diǎn)的規(guī)模,該功能在社區(qū) Kubernetes-1.14 中已經(jīng)默認(rèn)啟用。
在生產(chǎn)集群中,出于性能和可用性的考慮,通常會(huì)部署多個(gè)節(jié)點(diǎn)組成高可用 Kubernetes 集群。但在高可用集群實(shí)際的運(yùn)行中,可能會(huì)出現(xiàn)多個(gè) API Server 之間的負(fù)載不均衡,尤其是在集群升級(jí)或部分節(jié)點(diǎn)發(fā)生故障重啟的時(shí)候。這給集群的穩(wěn)定性帶來了很大的壓力,原本計(jì)劃通過高可用的方式分?jǐn)?API Server 面臨的壓力,但在極端情況下所有壓力又回到了一個(gè)節(jié)點(diǎn),導(dǎo)致系統(tǒng)響應(yīng)時(shí)間變長(zhǎng),甚至擊垮該節(jié)點(diǎn)繼而導(dǎo)致雪崩。
下圖為壓測(cè)集群中模擬的一個(gè) case,在三個(gè)節(jié)點(diǎn)的集群,API Server 升級(jí)后所有的壓力均打到了其中一個(gè) API Server 上,其 CPU 開銷遠(yuǎn)高于其他兩個(gè)節(jié)點(diǎn)。
解決負(fù)載均衡問題,一個(gè)自然的思路就是增加 load balancer。前文的描述中提到,集群中主要的負(fù)載是處理節(jié)點(diǎn)的心跳,那我們就在 API Server 與 kubelet 中間增加 lb,有兩個(gè)典型的思路:
通過壓測(cè)環(huán)境驗(yàn)證發(fā)現(xiàn),增加 lb 并不能很好的解決上面提到的問題,我們必須要深入理解 Kubernetes 內(nèi)部的通信機(jī)制。深入到 Kubernetes 中研究發(fā)現(xiàn),為了解決 tls 連接認(rèn)證的開銷,Kubernetes 客戶端做了很多的努力確?!氨M量復(fù)用同樣的 tls 連接”,大多數(shù)情況下客戶端 watcher 均工作在下層的同一個(gè) tls 連接上,僅當(dāng)這個(gè)連接發(fā)生異常時(shí),才可能會(huì)觸發(fā)重連繼而發(fā)生 API Server 的切換。其結(jié)果就是我們看到的,當(dāng) kubelet 連接到其中一個(gè) API Server 后,基本上是不會(huì)發(fā)生負(fù)載切換。為了解決這個(gè)問題,我們進(jìn)行了三個(gè)方面的優(yōu)化:
409 - too many requests
?提醒客戶端退避;當(dāng)自身負(fù)載超過一個(gè)更高的閾值時(shí),通過關(guān)閉客戶端連接拒絕請(qǐng)求;409
?時(shí),嘗試重建連接切換 API Server;定期地重建連接切換 API Server 完成洗牌;如上圖左下角監(jiān)控圖所示,增強(qiáng)后的版本可以做到 API Server 負(fù)載基本均衡,同時(shí)在顯示重啟兩個(gè)節(jié)點(diǎn)(圖中抖動(dòng))時(shí),能夠快速的自動(dòng)恢復(fù)到均衡狀態(tài)。
List-Watch 是 Kubernetes 中 Server 與 Client 通信最核心一個(gè)機(jī)制,etcd 中所有對(duì)象及其更新的信息,API Server 內(nèi)部通過 Reflector 去 watch?etcd 的數(shù)據(jù)變化并存儲(chǔ)到內(nèi)存中,controller/kubelets 中的客戶端也通過類似的機(jī)制去訂閱數(shù)據(jù)的變化。
在 List-Watch 機(jī)制中面臨的一個(gè)核心問題是,當(dāng) Client 與 Server 之間的通信斷開時(shí),如何確保重連期間的數(shù)據(jù)不丟,這在 Kubernetes 中通過了一個(gè)全局遞增的版本號(hào) resourceVersion
?來實(shí)現(xiàn)。如下圖所示 Reflector 中保存這當(dāng)前已經(jīng)同步到的數(shù)據(jù)版本,重連時(shí) Reflector 告知 Server 自己當(dāng)前的版本(5),Server 根據(jù)內(nèi)存中記錄的最近變更歷史計(jì)算客戶端需要的數(shù)據(jù)起始位置(7)。
這一切看起來十分簡(jiǎn)單可靠,但是...
在 API Server 內(nèi)部,每個(gè)類型的對(duì)象會(huì)存儲(chǔ)在一個(gè)叫做 storage
?的對(duì)象中,比如會(huì)有:
每個(gè)類型的 storage 會(huì)有一個(gè)有限的隊(duì)列,存儲(chǔ)對(duì)象最近的變更,用于支持 watcher 一定的滯后(重試等場(chǎng)景)。一般來說,所有類型的類型共享一個(gè)遞增版本號(hào)空間(1, 2, 3, ..., n),也就是如上圖所示,pod 對(duì)象的版本號(hào)僅保證遞增不保證連續(xù)。Client 使用 List-Watch 機(jī)制同步數(shù)據(jù)時(shí),可能僅關(guān)注 pods 中的一部分,最典型的 kubelet 僅關(guān)注和自己節(jié)點(diǎn)相關(guān)的 pods,如上圖所示,某個(gè) kubelet 僅關(guān)注綠色的 pods (2, 5)。
因?yàn)?storage 隊(duì)列是有限的(FIFO),當(dāng) pods 的更新時(shí)隊(duì)列,舊的變更就會(huì)從隊(duì)列中淘汰。如上圖所示,當(dāng)隊(duì)列中的更新與某個(gè) Client 無關(guān)時(shí),Client 進(jìn)度仍然保持在 rv=5,如果 Client 在 5 被淘汰后重連,這時(shí)候 API Server 無法判斷 5 與當(dāng)前隊(duì)列最小值(7)之間是否存在客戶端需要感知的變更,因此返回 Client too old version err
?觸發(fā) Client 重新 list 所有的數(shù)據(jù)。為了解決這個(gè)問題,Kubernetes 引入 Watch bookmark
?機(jī)制:
bookmark 的核心思想概括起來就是在 Client 與 Server 之間保持一個(gè)“心跳”,即使隊(duì)列中無 Client 需要感知的更新,Reflector 內(nèi)部的版本號(hào)也需要及時(shí)的更新。如上圖所示,Server 會(huì)在合適的適合推送當(dāng)前最新的 rv=12 版本號(hào)給 Client,使得 Client 版本號(hào)跟上 Server 的進(jìn)展。bookmark 可以將 API Server 重啟時(shí)需要重新同步的事件降低為原來的 3%(性能提高了幾十倍),該功能有阿里云容器平臺(tái)開發(fā),已經(jīng)發(fā)布到社區(qū) Kubernetes-1.15 版本中。
除 List-Watch 之外,另外一種客戶端的訪問模式是直接查詢 API Server,如下圖所示。為了保證客戶端在多個(gè) API Server 節(jié)點(diǎn)間讀到一致的數(shù)據(jù),API Server 會(huì)通過獲取 etcd 中的數(shù)據(jù)來支持 Client 的查詢請(qǐng)求。從性能角度看,這帶來了幾個(gè)問題:
Quorum read
?,這個(gè)查詢開銷是集群級(jí)別,無法擴(kuò)展的。為了解決這個(gè)問題,我們?cè)O(shè)計(jì)了 API Server 與 etcd 的數(shù)據(jù)協(xié)同機(jī)制,確保 Client 能夠通過 API Server 的 cache 獲取到一致的數(shù)據(jù),其原理如下圖所示,整體工作流程如下:
這個(gè)方式并未打破 Client 的一致性模型(感興趣的可以自己論證一下),同時(shí)通過 cache 響應(yīng)用戶請(qǐng)求時(shí)我們可以靈活的增強(qiáng)查詢能力,比如支持 namespace nodename/labels 索引。該增強(qiáng)大幅提高了 API Server 的讀請(qǐng)求處理能力,在萬臺(tái)規(guī)模集群中典型的 describe node 的時(shí)間從原來的 5s 降低到 0.3s(觸發(fā)了 node name 索引),其他如 get nodes 等查詢操作的效率也獲得了成倍的增長(zhǎng)。
在 10k node 的生產(chǎn)集群中,Controller 中存儲(chǔ)著近百萬的對(duì)象,從 API Server 獲取這些對(duì)象并反序列化的開銷是無法忽略的,重啟 Controller 恢復(fù)時(shí)可能需要花費(fèi)幾分鐘才能完成這項(xiàng)工作,這對(duì)于阿里巴巴規(guī)模的企業(yè)來說是不可接受的。為了減小組件升級(jí)對(duì)系統(tǒng)可用性的影響,我們需要盡量的減小 controller 單次升級(jí)對(duì)系統(tǒng)的中斷時(shí)間,這里通過如下圖所示的方案來解決這個(gè)問題:
通過這個(gè)方案,我們將 controller 中斷時(shí)間降低到秒級(jí)別(升級(jí)時(shí) < 2s),即使在異常宕機(jī)時(shí),備僅需等待 leader lease 的過期(默認(rèn) 15s),無需要花費(fèi)幾分鐘重新同步數(shù)據(jù)。通過這個(gè)增強(qiáng),顯著的降低了 controller MTTR,同時(shí)降低了 controller 恢復(fù)時(shí)對(duì) API Server 的性能沖擊。該方案同樣適用于 scheduler。
由于歷史原因,阿里巴巴的調(diào)度器采用了自研的架構(gòu),因時(shí)間的關(guān)系本次分享并未展開調(diào)度器部分的增強(qiáng)。這里僅分享兩個(gè)基本的思路,如下圖所示:
阿里巴巴通過一系列的增強(qiáng)與優(yōu)化,成功將 Kubernetes 應(yīng)用到生產(chǎn)環(huán)境并達(dá)到了單集群 10000 節(jié)點(diǎn)的超大規(guī)模,具體包括:
通過這一系列功能增強(qiáng),阿里巴巴成功將內(nèi)部最核心的業(yè)務(wù)運(yùn)行在上萬節(jié)點(diǎn)的 Kubernetes 集群之上,并經(jīng)歷了 2019 年天貓 618 大促的考驗(yàn)。
作者簡(jiǎn)介:
曾凡松(花名:逐靈),阿里云云原生應(yīng)用平臺(tái)高級(jí)技術(shù)專家。
有豐富的分布式系統(tǒng)設(shè)計(jì)研發(fā)經(jīng)驗(yàn)。在集群資源調(diào)度這一領(lǐng)域,曾負(fù)責(zé)的自研調(diào)度系統(tǒng)管理了數(shù)十萬規(guī)模的節(jié)點(diǎn),在集群資源調(diào)度、容器資源隔離、不同工作負(fù)載混部等方面有豐富的實(shí)踐經(jīng)驗(yàn)。當(dāng)前主要負(fù)責(zé) Kubernetes 在阿里內(nèi)部的規(guī)模化落地,將 Kubernetes 應(yīng)用于阿里內(nèi)部的最核心電商業(yè)務(wù),提高了應(yīng)用發(fā)布效率及集群資源利用率,并穩(wěn)定支撐了 2018 雙十一 及 2019 618 大促。
“ 阿里巴巴云原生微信公眾號(hào)(ID:Alicloudnative)關(guān)注微服務(wù)、Serverless、容器、Service Mesh 等技術(shù)領(lǐng)域、聚焦云原生流行技術(shù)趨勢(shì)、云原生大規(guī)模的落地實(shí)踐,做最懂云原生開發(fā)者的技術(shù)公眾號(hào)?!?/strong>
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)cdcxhl.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。