本文介紹了美團在如何解決大規模叢集管理的難題、設計優秀且合理的叢集排程系統方面的實踐,闡述了美團在落地以Kubernetes為代表的雲原生技術時,比較關心的問題、挑戰以及對應的推進策略。同時本文也介紹了針對美團業務需求場景做的一些特色支援,希望本文能夠對雲原生領域感興趣的同學有所幫助或者啟發。
導語
叢集排程系統在企業資料中心中佔有舉足輕重的地位,隨著叢集規模與應用數量的不斷激增,開發者處理業務問題的複雜度也顯著提升。如何解決大規模叢集管理的難題,設計優秀且合理的叢集排程系統,做到保穩定,降成本,提效率?本文將會逐一進行解答。
| 備註:文章最早釋出於《新程式設計師003》雲原生時代的開發者專欄。
叢集排程系統介紹
叢集排程系統,又被稱為資料中心資源排程系統,普遍用來解決資料中心的資源管理和任務排程問題,它的目標是做到資料中心資源的有效利用,提升資源的利用率,併為業務方提供自動化的運維能力,降低服務的運維管理成本。工業界比較知名的叢集排程系統,如開源的OpenStack、YARN、Mesos和Kubernetes等等,再如知名網際網路公司Google的Borg、微軟的Apollo、百度的Matrix、阿里巴巴的Fuxi和ASI。
叢集排程系統作為各網際網路公司核心的IaaS基礎設施,在近十幾年經歷了多次架構演進。伴隨著業務從單體架構向SOA(面向服務的架構)演進和微服務的發展,底層的IaaS設施也從物理機裸機時代逐步跨越到容器時代。雖然在演進過程中我們要處理的核心問題沒有改變,但由於叢集規模和應用數量的急劇膨脹,問題的複雜度也成指數級增長。本文將闡述大規模叢集管理的挑戰和叢集排程系統的設計思路,並以美團叢集排程系統落地實踐為例,講述通過打造多叢集統一排程服務,持續提升資源的利用率,提供Kubernetes引擎服務賦能PaaS元件,為業務提供更好的計算服務體驗等一系列雲原生實踐。
大規模叢集管理的難題
眾所周知,業務快速增長帶來的是伺服器規模和資料中心數量的暴增。對於開發者而言,在大規模叢集排程系統的業務場景下,必須要解決的兩個難題是:
- 如何管理好資料中心大規模叢集部署排程,特別是在跨資料中心場景下,如何實現資源的彈性和排程能力,在保障應用服務質量的前提下儘可能地提升資源的利用率,充分降低資料中心成本。
- 如何改造底層基礎設施,為業務方打造雲原生作業系統,提升計算服務體驗,實現應用的自動化容災響應和部署升級等,減少業務方對底層資源管理的心智負擔,讓業務方可以更專注於業務本身。
運營大規模叢集的挑戰
為了在真實的生產環境解決上述兩個難題,具體又可以再拆分成以下四個大規模叢集運營管理挑戰:
- 如何解決使用者多樣化需求並快速響應。業務的排程需求和場景豐富且動態多變,作為叢集排程系統這樣的平臺型服務,一方面需要能夠快速交付功能,及時滿足業務需求;另一方面還需要把平臺打造得足夠通用,將業務個性化需求抽象為可落地到平臺的通用能力,並長期進行迭代。這非常考驗平臺服務團隊的技術演進規劃,因為一不小心,團隊就會陷入無休止的業務功能開發中,雖然滿足了業務需求,卻會造成團隊工作低水平重複的現象。
- 如何提高線上應用資料中心的資源利用率且同時保障應用服務質量。資源排程一直是業界公認的難題,隨著雲端計算市場快速發展,各雲端計算廠商不斷加大對資料中心的投入。資料中心的資源使用率卻非常低,更加劇了問題的嚴重性。Gartner調研發現全球資料中心伺服器CPU利用率只有6%~12%,即使是亞馬遜彈性計算雲平臺(EC2,Elastic Compute Cloud)也只有7%~17%的資源利用率,可見資源浪費有多嚴重。究其原因,線上應用對於資源利用率非常敏感,業界不得不預留額外資源以保障重要應用的服務質量(QoS,Qualityof Service)。叢集排程系統需要在多應用混合執行時消除應用間的干擾,實現不同應用之間的資源隔離。
- 如何為應用,特別是有狀態應用提供例項異常自動處理,遮蔽機房差異,降低使用者對底層的感知。隨著服務應用規模的持續擴大,以及雲端計算市場的日趨成熟,分散式應用往往會配置在不同地域的資料中心,甚至是跨越不同的雲環境,實現了多雲或混合雲部署。而叢集排程系統需要為業務方提供統一的基礎設施,實現混合多雲架構,遮蔽底層的異構環境。同時降低應用運維管理的複雜性,提升應用的自動化程度,為業務提供更好的運維體驗。
- 如何解決單叢集過大或叢集數量過多,而帶來的與叢集管理相關的效能和穩定性風險。叢集本身的生命週期管理複雜度會伴隨叢集規模和數量的增多而增大。以美團為例,我們所採取的兩地多中心多叢集方案,雖然在一定程度上規避了叢集規模過大的隱患,解決了業務隔離性、地域延遲等問題。隨著邊緣叢集場景和資料庫等PaaS元件上雲需求的出現,可以預見小叢集數量將會有明顯的上漲趨勢。隨之帶來的是叢集管理複雜度、監控配置成本、運維成本的明顯增加,這時叢集排程系統需要提供更有效的操作規範,並保證操作安全性、報警自愈和變更效率。
設計叢集排程系統時的取捨
為了解決上述挑戰,一個好的叢集排程器將發揮關鍵作用。但現實中從來不存在一個完美的系統,所以在設計叢集排程系統時,我們需要根據實際場景在幾個矛盾中做出取捨:
- 叢集排程系統的系統吞吐量和排程質量。系統吞吐量是我們通常評估一個系統好壞很重要的標準,但在面向線上服務的叢集排程系統裡更重要的是排程質量。因為每次排程結果的影響是長期的(數天、數週甚至數月),非異常情況不會調整。所以如果排程結果錯誤,會直接導致服務時延增高。而排程質量越高則意味著需要考慮的計算約束條件越多,而且排程效能越差的話,系統吞吐量越低。
- 叢集排程系統的架構複雜度和可擴充套件性。系統對上層PaaS使用者開放的功能和配置越多,通過支援更多功能來提升使用者體驗(比如支援應用資源搶佔回收和應用例項異常自愈),也就意味著系統複雜度越高,各子系統越容易發生衝突。
- 叢集排程系統的可靠性和單叢集規模。單叢集規模越大,則可排程範圍則越大,但對叢集的可靠性挑戰也越大,因為爆炸半徑會增加,出現故障的影響也越大。單叢集規模較小的情況下,雖然可以提升排程併發度,但可排程範圍變小,排程失敗概率變高,且叢集管理複雜度變大。
目前,業內的叢集排程系統按照架構區分,可以分為單體式排程器、兩級排程器、共享狀態排程器、分散式排程器和混合排程器這五種不同架構(見下圖1),都是根據各自的場景需求做了不同的選擇,沒有絕對的好與壞。
- 單體式排程器使用複雜的排程演算法結合叢集的全域性資訊,計算出高質量的放置點,不過延遲較高。如Google的Borg系統、開源的Kubernetes系統。
- 兩級排程器通過將資源排程和作業排程分離,解決單體式排程器的侷限性。兩級排程器允許根據特定的應用做不同的作業排程邏輯,且同時保持了不同作業之間共享叢集資源的特性,可是無法實現高優先順序應用的搶佔。具有代表性的系統是Apache Mesos和Hadoop YARN。
- 共享狀態排程器通過半分散式的方式來解決兩級排程器的侷限性,共享狀態下的每個排程器都擁有一份叢集狀態的副本,且排程器獨立對叢集狀態副本進行更新。一旦本地的狀態副本發生變化,整個叢集的狀態資訊就會被更新,但持續資源爭搶會導致排程器效能下降。具有代表性的系統是Google的Omega和微軟的Apollo。
- 分散式排程器使用較為簡單的排程演算法以實現針對大規模的高吞吐、低延遲並行任務放置,但由於排程演算法較為簡單並缺乏全域性的資源使用視角,很難達到高質量的作業放置效果,代表性系統如加州大學的Sparrow。
- 混合排程器將工作負載分散到集中式和分散式元件上,對長時間執行的任務使用複雜演算法,對短時間執行的任務則依賴於分散式佈局。微軟Mercury就採取了這種這種方案。
所以,如何評價一個排程系統的好壞,主要取決於實際的排程場景。以業內使用最廣泛的YARN和Kubernetes為例,雖然兩個系統都是通用資源排程器,實際上YARN專注於離線批處理短任務,Kubernetes專注於線上長時間執行的服務。除了架構設計和功能的不同(Kubernetes是單體式排程器,YARN是兩級排程器),二者的設計理念和視角也不同。YARN更專注任務,關注資源複用,避免遠端資料多次拷貝,目標是以更低成本、更高速度執行任務。Kubernetes更專注服務狀態,關注錯峰、服務畫像、資源隔離,目標是保障服務質量。
美團叢集排程系統演變之路
美團在落地容器化的過程中,根據業務場景需求,叢集排程系統核心引擎由OpenStack轉變為Kubernetes,並在2019年底完成了線上業務容器化覆蓋率超過了98%的既定目標。但依然面臨資源利用率低、運維成本高等問題:
- 叢集整體的資源利用率不高。如CPU資源平均利用率還處於業內平均水平,相較於其他一線網際網路公司差距較大。
- 有狀態服務的容器化率程度不夠,特別是MySQL、Elasticsearch等產品沒有使用容器,業務運維成本和資源成本存在較大的優化空間。
- 從業務需求考慮,VM產品會長期存在,VM排程和容器排程是兩套環境,導致團隊虛擬化產品運維成本較高。
因此,我們決定開始對叢集排程系統進行雲原生改造。打造一個具有多叢集管理和自動化運維能力、支援排程策略推薦和自助配置、提供雲原生底層擴充套件能力,並在保障應用服務質量的前提下提升資源使用率的大規模高可用排程系統。核心工作圍繞保穩定、降成本、提效率三大方向來構建排程系統。
- 保穩定:提升排程系統的健壯性、可觀測性;降低系統各模組之間的耦合,減少複雜度;提升多叢集管理平臺的自動化運維能力;優化系統核心元件效能;確保大規模叢集的可用性。
- 降成本:深度優化排程模型,打通叢集排程和單機排程鏈路。從資源靜態排程轉向資源動態排程,引入離線業務容器,形成自由競爭與強控結合,在保障高優業務應用服務質量的前提下,提升資源使用率,降低IT成本。
- 提效率:支援使用者自助調整排程策略,滿足業務個性化需求,積極擁抱雲原生領域,為PaaS元件提供包括編排、排程、跨叢集、高可用等核心能力,提升運維效率。
最終,美團叢集排程系統架構按照領域劃分為三層(見上圖2),排程平臺層、排程策略層、排程引擎層:
- 平臺層負責業務接入,打通美團基礎設施,封裝原生介面和邏輯,提供容器管理介面(擴容、更新、重啟、縮容)等功能。
- 策略層提供多叢集統一排程能力,持續優化排程演算法和策略,結合業務的服務等級和敏感資源等資訊,通過服務分級提升CPU使用率和分配率。
- 引擎層提供Kubernetes服務,保障多個PaaS元件的雲原生叢集穩定性,並把通用能力下沉到編排引擎,降低業務雲原生落地的接入成本。
通過精細化運營和產品功能打磨,我們一方面統一納管了美團近百萬的容器/虛擬機器例項,另一方面將資源利用率從業內平均水平提升到了一流水平,同時還支撐了PaaS元件的容器化和雲原生落地。
多叢集統一排程:提升資料中心資源利用率
評估考核叢集排程系統的好壞,資源利用率是最重要的指標之一。因此,雖然我們在2019年完成了容器化,不過容器化不是目的,只是手段。我們的目標是通過從VM技術棧切換到容器技術棧,為使用者帶來更多的收益,比如全面降低使用者的計算成本。
而提升資源利用率受限於叢集的個別熱點宿主,一旦擴容,業務容器就有可能擴容到熱點宿主,業務的效能指標如TP95耗時會出現波動,以至於我們只能像業界其他公司一樣,通過增加資源冗餘來保障服務質量。究其原因,Kubernetes排程引擎的分配方式僅簡單考慮了Request/Limit Quota(Kubernetes為容器設定了請求值Request和約束值Limit,作為使用者申請容器的資源配額),屬於靜態資源分配。導致不同宿主機雖然分配了同樣多的資源,卻因宿主機的服務差異性使得宿主機的資源利用率也存在較大的差異。
在學術界和工業界中,有兩種常用的方法解決資源使用效率和應用服務質量之間的矛盾。第一種方法是通過高效的任務排程器在全域性角度解決;第二種方法是通過單機資源管理手段來加強應用之間的資源隔離。不管是哪一種方法,都意味著我們需要全面掌握叢集狀態,所以我們做了三件事:
- 系統地建立了叢集狀態、宿主狀態、服務狀態的關聯,並結合排程模擬平臺,綜合考慮了峰值利用率和平均利用率,實現了基於宿主歷史負載和業務實時負載的預測和排程。
- 通過自研的動態負載調節系統和跨叢集重排程系統,實現了叢集排程和單機排程鏈路的聯動,根據業務分級實現了不同資源池的服務質量保障策略。
- 經過三版迭代,實現了自有叢集聯邦服務,較好地解決了資源預佔和狀態資料同步問題,提升了叢集間的排程併發度,實現了計算分離、叢集對映、負載均衡和跨叢集編排控制(見下圖3)。
叢集聯邦服務第三版本(圖3)按照模組拆分為Proxy層和Worker層,獨立部署:
- Proxy層會綜合叢集狀態的因子及權重選擇合適的叢集進行排程,並選擇合適的Worker分發請求。Proxy模組使用etcd做服務註冊、選主和發現,Leader節點負責排程時預佔任務,所有節點都能負責查詢任務。
- Worker層對應處理一部分Cluster的查詢請求,當某叢集任務阻塞,可以快速擴容一臺對應的Worker例項緩解問題。當單叢集規模較大時會對應多個Worker例項,Proxy將排程請求分發給多個Worker例項處理,提升排程併發度,並減少每一個Worker的負載。
最終通過多叢集統一排程,我們實現了從靜態資源排程模型轉向動態資源排程模型,從而降低了熱點宿主比例,減少了資源碎片比例,保障了高優業務應用的服務質量,將線上業務叢集的伺服器CPU利用率均值提升了10個百分點。叢集資源利用率均值計算方式:Sum(nodeA.cpu.當前使用核數 + nodeB.cpu.當前使用核數 + xxx) / Sum(nodeA.cpu.總核數 + nodeB.cpu.總核數 + xxx),一分鐘一個點,當天所有值取平均。
排程引擎服務:賦能PaaS服務雲原生落地
叢集排程系統除了解決資源排程的問題之外,還解決服務使用計算資源的問題。正如《Software Engineering at Google》一書中提到的,叢集排程系統作為Compute as a Service中關鍵元件之一,既要解決資源排程(從物理機拆解到CPU/Mem這樣的資源維度)和資源競爭(解決“吵鬧鄰居”),還需要解決應用管理(例項自動化部署、環境監控、異常處理、保障服務例項數、確定業務需求資源量、不同服務種類等)。而且從某種程度上來說應用管理比資源排程更重要,因為這會直接影響業務的開發運維效率和服務容災效果,畢竟網際網路的人力成本比機器成本更高。
複雜的有狀態應用的容器化一直是業界難題,因為這些不同場景下的分散式系統中通常維護了自己的狀態機。當應用系統發生擴縮容或升級時,如何保證當前已有例項服務的可用性,以及如何保證它們之間的可連通性,是相較無狀態應用複雜許多的棘手問題。雖然我們已經把無狀態服務都容器化了,但我們還沒有充分發揮出一個良好的叢集排程系統的全部價值。如果要想管好計算資源,必須管理好服務的狀態,做到資源和服務分離,提升服務韌性,而這也是Kubernetes引擎所擅長的。
我們基於美團優化定製的Kubernetes版本,打造了美團Kubernetes引擎服務MKE:
- 加強叢集運維能力,完善了叢集的自動化運維能力建設,包括叢集自愈、報警體系、Event日誌分析等,持續提升叢集的可觀測性。
- 豎立重點業務標杆,與幾個重要的PaaS元件深入合作,針對使用者的痛點如Sidecar升級管理、Operator灰度迭代、報警分離做快速優化,滿足使用者的訴求。
- 持續改進產品體驗,持續優化Kubernetes引擎,除了支援使用者使用自定義Operator之外,也提供了通用的排程和編排框架(見圖4),幫助使用者以更低的成本接入MKE,獲得技術紅利。
在我們推進雲原生落地過程中,一個廣泛被關注的問題是:基於Kubernetes雲原生方式來管理有狀態應用,相比於之前自己打造管理平臺有什麼區別?
對於這個問題,需要從問題根源——可運維性考慮:
- 基於Kubernetes意味著系統做到了閉環,不用擔心兩套系統經常出現的資料不一致問題。
- 異常響應可以做到毫秒級別,降低了系統的RTO(Recovery Time Objective,即恢復時間目標,主要指所能容忍的業務停止服務的最長時間,也是從災難發生到業務系統恢復服務功能所需要的最短時間週期)。
- 系統運維複雜度也降低了,服務做到了自動化容災。除了服務本身之外,服務依賴的配置和狀態資料都可以一起恢復。
- 相比於之前各個PaaS元件“煙囪式”的管理平臺,通用能力可以下沉到引擎服務,減少開發維護成本,而通過依託於引擎服務,可以遮蔽底層異構環境,實現跨資料中心和多雲環境的服務管理。
未來展望:構建雲原生作業系統
我們認為,雲原生時代的叢集管理,會從之前的管理硬體、資源等職能全面轉變為以應用為中心的雲原生作業系統。以此為目標,美團叢集排程系統還需從以下幾方面發力:
- 應用鏈路交付管理。隨著業務規模和鏈路複雜度的增大,業務所依賴的PaaS元件和底層基礎設施的運維複雜度早已超過普遍認知,對於剛接手專案的新人更是難上加難。所以我們需要支援業務通過宣告式配置交付服務並實現自運維,給業務提供更好的運維體驗,提升應用的可用性和可觀測性,減少業務對底層資源管理的負擔。
- 邊緣計算解決方案。隨著美團業務場景的不斷豐富,業務對邊緣計算節點的需求增長,比預期快很多。我們會參考業內最佳實踐,形成適合在美團落地的邊緣解決方案,儘快為有需求的服務提供邊緣計算節點管理能力,實現雲邊端協同。
- 在離線混部能力建設。線上業務叢集的資源利用率提升是有上限的,根據Google在論文《Borg: the Next Generation》中披露的2019年資料中心叢集資料,刨去離線任務,線上任務的資源利用率僅為30%左右,這也說明了再往上提升風險較大,投入產出比不高。後續,美團叢集排程系統將持續探索在離線混部,不過由於美團的離線機房相對獨立,我們的實施路徑會與業界的普遍方案有所不同,會先從線上服務和近實時任務的混部開始,完成底層能力的構建,再探索線上任務和離線任務的混部。
總結
美團叢集排程系統在設計時,整體遵循合適原則,在滿足業務基本需求的情況下,保證系統穩定後再逐步完善架構,提升效能和豐富功能。因此,我們選擇了:
- 在系統吞吐量和排程質量中我們選擇優先滿足業務對系統的吞吐量需求,不過度追求單次排程質量,而是通過重排程調整完善。
- 在架構複雜度和可擴充套件性中我們選擇降低系統各模組之間的耦合,減少系統複雜度,擴充套件功能必需可降級。
- 在可靠性和單叢集規模中我們選擇通過多叢集統一排程來控制單叢集規模,保障系統可靠性,減少爆炸半徑。
未來,我們也會根據同樣的邏輯持續優化迭代美團的叢集排程系統,徹底轉變為以應用為中心的雲原生作業系統。
作者簡介
譚霖,來自美團基礎研發平臺/基礎技術部。
閱讀美團技術團隊更多技術文章合集
前端 | 演算法 | 後端 | 資料 | 安全 | 運維 | iOS | Android | 測試
| 在公眾號選單欄對話方塊回覆【2021年貨】、【2020年貨】、【2019年貨】、【2018年貨】、【2017年貨】等關鍵詞,可檢視美團技術團隊歷年技術文章合集。
| 本文系美團技術團隊出品,著作權歸屬美團。歡迎出於分享和交流等非商業目的轉載或使用本文內容,敬請註明“內容轉載自美團技術團隊”。本文未經許可,不得進行商業性轉載或者使用。任何商用行為,請傳送郵件至tech@meituan.com申請授權。