美團點評容器平臺HULK的排程系統
本文授權轉載自微信公眾號:美團點評技術團隊
美團點評作為國內最大的O2O平臺,業務熱度的高峰低谷非常顯著且規律,如果遇到節假日或促銷活動,流量還會在短時間內出現成倍的增長。過去傳統虛擬機器的服務執行及部署機制在應對服務快速擴容、縮容需求中存在諸多不足:
- 資源例項建立慢,需要預先安裝好執行所需的環境,比如JDK等。
- 擴容後的例項,需要經過程式碼部署流程,一些情況下還需要修改配置後才能承接流量。
- 資源申請容易回收難,促銷活動後做相關資源的回收下線會比較漫長。
- 由於業務存在典型的高峰低谷,為保障業務穩定,資源例項數要保障能抗高峰期容量峰值的1-2倍,從而導致非高峰期資源大量閒置,整體利用效率低。
注意到上面這些問題後,我們經過調研與測試,結合業界的實踐經驗,決定基於Docker容器技術來實現服務的彈性伸縮,有效應對快速擴縮容需求、提升資源利用效率。
Docker容器技術也是一類虛擬化技術,不同於虛擬機器的硬體虛擬化,容器是基於作業系統核心的隔離機制實現。容器省去了模擬底層硬體、指令等操作,直接基於宿主機核心,並隔離出獨立的系統環境、加以資源限制,能有效提升啟動速度和效能。
HULK容器平臺簡介
美團點評基礎架構團隊在2015年中旬啟動了公司級的容器叢集管理及彈性伸縮平臺——HULK專案,目標是提供Docker容器平臺,推動公司的服務容器化,實現自動的彈性擴容、縮容,提升資源利用率、業務運維效率並降低IT運維成本。
HULK是美國漫威漫畫旗下超級英雄“綠巨人”,擁有強大的變身能。變身後的綠巨人對各類疾病、射線、毒藥及物理攻擊有很高的免疫力,加上超強的再生能力使得其非常強大。
我們選擇HULK作為專案名,就是希望美團點評服務在接入HULK之後可以擁有綠巨人般強大的變身能力(彈性擴縮),進而在此基礎上提升服務的健壯性、穩定性及資源利用率。
HULK容器平臺系統層次圖
在HULK所有模組中,排程系統負責對資源池進行統一的排程分配與管理。主要職責包括:
- 接受上層彈性伸縮及叢集管理模組的資源申請、回收請求,執行資源分配。
- 綜合多種資源利用、服務優化的排程演算法,決策最優資源部署位置,提高資源利用率、節約成本並保障服務穩定性。
- 對接雲平臺IaaS層。
本文將主要對HULK容器平臺的排程系統進行介紹,包括當前排程系統的設計、考量指標、相關演算法等。
HULK排程系統介紹
核心指標
從HULK彈性排程系統的設計以及後續的演進過程來看,一個完善的排程系統主要需要關注以下三個指標:
排程系統核心指標
- 資源利用率:即提高整體物理叢集的資源利用率。一個優秀的排程系統可以把資源利用率提高到30%~70%,而簡陋的排程系統甚至會使資源利用率降低到10%以下。
- 業務最優化:即保障執行業務的穩定高可用,以及服務相互呼叫的優化。比如,如果排程系統一味的追求資源利用率,將宿主機上堆砌超過其負載能力的例項,又或一臺宿主機/機架的故障會影響到一個服務下所有例項的執行,都在業務穩定性上打了折扣。
- 併發排程能力:排程系統請求處理能力的體現。一個大規模的物理叢集上,往往運行了數以千百計的業務,當出現排程請求高峰的場景下,排程系統要有能力在短時間內給出答案,即使這個答案可能只是全域性近似最優解。
排程系統設計難題
排程系統設計的難題,在於幾個排程核心指標在實現上存在的矛盾關係,類似於CAP理論中的三要素,無法同時滿足。
在CAP理論中,Consistency(一致性)、Availability(可用性)與Partition Tolerance(分割槽容錯性)無法同時滿足。如果追求可用性與分割槽容錯性,則需要犧牲強一致性,只能保證最終一致性;而如果要保障強一致性與可用性,如果出現網路故障將無法正常工作。
類似的,在排程系統中,如果要追求極限的資源利用率,則每一次排程的結果必須是基於當前資源池狀態的最優解,因此不管排程佇列還是排程處理計算只能是“單行道”,效率低下是毋庸置疑的,大批量伸縮排程場景下任務堆積嚴重。
如果追求高效的排程能力,則所有排程請求需要併發處理。但底層資源池只有一個,很容易出現多個排程請求爭搶同一份資源的情況。這種情況下,就要採取措施來保障資源層資料一致性,且排程所得的結果不能保證是全域性最優解(無法最大化資源利用率)。
業界解決思路
Mesos
Mesos採用雙層排程的理念,把應用相關的管理交由上層Framework來做,這也是Mesos與Kubernetes等系統最大的不同點。Mesos只是分散式系統核心,即管理分散式資源、對外暴露標準介面來操作叢集資源(遮蔽資源層細節)。在雙層排程的模式下,Mesos只負責在不同的Framework之間分派資源,將資源作為Offer的形式提供給Framework。
這種做法把上述排程設計矛盾丟給了Framework,但如果只從提供資源Offer的角度來看,這是一種併發排程的形式(同一個Mesos資源池,資源要提供給上層多個Framework)。Mesos解決併發排程、資源池資料一致性的方案是,資源Offer同時只會分派給一個Framework。這種資源分派方式是悲觀的,資源被Framework獨佔,直到返回或超時。
顯然,這種悲觀鎖導致了Mesos雙層排程的併發粒度較小,但是在多數情況下,同個Mesos叢集上層的Framework數量不會太多,有時只有一個Framework在獨享資源,因此這種悲觀鎖的方案一般不會存在分配排程的瓶頸問題。
Omega
Omega同樣採用了將資源分派給上層應用的排程方式,與Mesos的悲觀鎖不同,Omega採用了樂觀鎖(MVCC,基於多版本的併發訪問控制)解決併發排程的問題,因此Omega也被稱為共享狀態排程器。
由於將資源層資訊作為共享資料提供給上層所有應用,Omega為了解決資料一致性,會對所有應用排程的提交衝突做解決,本質上是為每個節點維護了一個狀態關係資料庫。從這個角度看,Omega也存在一些缺點:
- 共享排程時衝突發生的頻率,直接影響了整體排程器的效能。
- 由於沒有集中的排程模組,難以對所有資源分組(Namespace)或使用者的資源使用量做精確限制。
- 上層排程器數量仍然不能很多,並行分發完整的叢集狀態的開銷較大。
Borg與Kubernetes
Borg據說現在已經逐漸演進吸收了Omega的很多設計思想,包括共享狀態排程模式,然而Kubernetes預設排程plugin的做法仍然是序列處理佇列中的排程任務,這也符合Kubernetes追求的簡潔優雅。
HULK排程解決方案
對於排程器設計難題,我們認為針對不同的場景,指標的側重點不同。
比如對於分散式系統的CAP,大多數網際網路場景下都會保證AP而捨棄C(只保證最終一致性),因為在網際網路分散式叢集規模大、網路故障頻發的場景下,要保證服務高可用只能犧牲強一致;而對於金融等涉及錢財的領域,則一般保證CA、捨棄P,即使遇到網路故障時只讀不寫,也必須保證強一致性。
同理對於排程器資源層設計,在網際網路高併發、彈性伸縮頻發的場景下,可以犧牲部分資源利用率從而提高併發排程能力。
HULK排程系統模型如下:
HULK排程模型
如圖,HULK排程系統分為排程請求佇列、排程計算模組、排程資源池這三個模組。工作流程如下:
- 上層HULK彈性伸縮系統,將排程任務ID寫入排程請求佇列中。
- HULK排程系統消費排程請求佇列,取出的排程任務ID將由排程計算池執行排程計算,決策出備選的部署位置,並向排程資源池申請資源。
- 排程資源池維護管理宿主機叢集資源,全部資源會提供給所有排程任務共享(與Omega類似),資源池中每個宿主機都有一個對應的Actor來負責管理。
排程計算模組(資源排程演算法)
HULK排程系統的排程計算方式與諸多業界排程系統類似,通過過濾+打分的方式篩選出“最優部署位置”:
HULK排程任務
- 宿主機(Host):排程資源池中共享的宿主機叢集,支援pool級別硬隔離,如線上服務與資料庫/快取的例項部署在不同的物理機叢集中;支援資源軟隔離,如線上服務離線任務混布部署,通過cgroups等機制隔離和設定權重。
- 過濾(Filter):預選(Predicates)的概念,通過超售、打散限制策略,排除掉一部分不合需求的宿主機。
- 打分(Rank):優選(Priorities)的概念,通過線上離線混布、不同資源型別混布、宿主機負載均衡等策略和對應權重,最終計算出一個rank值,根據rank值排序最終得出最優部署位置。
超售
不管是在傳統虛擬機器時代還是容器時代,超售始終是一個讓人又愛又恨的機制。
超售在一定程度上提高了叢集的資源利用率,因為機器在申請之時往往提高對真實資源消耗的預估,也就是在服務執行中,絕大多數情況用不到申請的所有資源。然而正因為超售,常常會帶來各種因資源爭用引發的服務異常,嚴重的情況下會導致宿主機上所有例項的不可用。
HULK容器排程同樣採用了超售機制,我們和IaaS層對資源進行了分類,可壓縮資源(如CPU、I/O等)使用超售機制,而不可壓縮資源(如Memory、Disk)只允許在一些測試環境超售。
相比於是否開啟超售,超售係數才是更為棘手的難題,它直接關係到資源利用率和服務穩定性。我們採用了超售上限+動態係數的機制,從IaaS層設定的超售上限固定了資源超售的上限比例,超過上限的例項建立將會失敗,而HULK排程系統會根據具體場景決定超售係數:
- 參考宿主機實時監控,如Load負載、記憶體使用、頻寬佔用等指標。
- 不同的例項型別(線上、離線)排程時超售係數不同。
業務例項打散
隨著物理叢集規模的擴大,宿主機故障頻次也會響應提高。如果一個線上服務的所有例項都部署在同一個宿主機上,很可能出現宿主機宕機後服務整體不可用,這是我們不能接受的。
業務使用者在HULK上配置不同的伸縮組,每個組對應了一個機房(資料中心),同個機房排程過程中會把同個服務的例項打散到不同的宿主機上,並優先在不同的交換機(機架)下。此外,針對資料庫/快取類的例項還有更嚴格的容災策略,比如Redis例項排程部署時,不允許同一個交換機下部署超過該Redis叢集25%的例項數量。
線上離線混布
一般來說,線上服務(如外賣、酒旅等服務)和離線任務(如定時任務、爬蟲、大資料計算)的需求資源型別和高峰/執行時間不盡相同,將這兩種例項進行混布可以有效提高物理叢集的資源利用率。
Borg系統中對prod與non-prod例項的一類處理方式是,根據宿主機上例項執行狀況,實時調整例項的資源配置。比如當線上服務迎來流量高峰、宿主機記憶體告急時,Borg會調整宿主機上non-prod任務的記憶體配額,以保證線上服務的穩定性。
但這種方案對Google中的部分C/C++服務適用,在美團點評Java服務的場景下,例項記憶體配額調整可能會導致OOM,而重啟服務非我們所願。
下圖是HULK某臺宿主機一天內的例項部署情況:
宿主機例項部署
目前HULK平臺上的離線任務主要還是定時任務與爬蟲,HULK針對線上離線混布場景從資源分配、時間錯峰上優化。根據美團點評的服務特性,HULK會盡量保證在早晚高峰的時期動態擴容線上服務承接流量,而在低峰期會對應縮容線上服務,並排程部署離線任務執行。
宿主機負載均衡
在排程計算的打分過程中,還會參考當前宿主機的負載情況。
HULK會從監控系統中獲取宿主機的系統監控資料,包括了CPU、Load、Memory、IO等指標。針對負載較低的宿主機我們給予較高的權重,而負載較高的宿主機,即使物理資源較為空閒,也不會優先選擇部署。
排程資源池(資源申請演算法)
當排程計算過程決策出一個根據排程rank權重排序好的資源可部署位置列表後,排程任務會取列表前n個元素,依次向對應的宿主機Actor申請資源,直到宿主機Actor返回批准(排程成功);如果取出的前n個均被拒絕,排程任務需要根據新的全域性資源池共享狀態再次排程計算。
如果兩個排程任務基於共享資源狀態同時申請某個宿主機上同一塊資源,則宿主機Actor會根據mailbox中訊息的順序來處理,資源先到先得,後者排程任務會繼續向下一個備選資源的宿主機Actor嘗試申請。
排程資源申請
這種資源排程的架構下,排程的併發度相比序列排程有了顯著的提高,即使出現提交衝突,重試機制也是非常輕量的,一般都可以在前n次之內完成。
這裡另一個核心問題在於n取值的權衡。如果n取值1,則每次失敗後就需要根據當前的叢集資源狀態重新排程計算,這種情況下排程資源利用率較高,但效率較低;而若n取值大於1,則重試後的排程位置往往並非當前最佳排程位置,且n越大這裡的最優排程偏差就越大。我們考慮的是根據當前整個系統中的排程請求數量來確定這個動態的n變數取值,當排程任務較少時n取較小值,當排程任務較多、彈性伸縮頻繁時,n的取值會相應調大。
排程模式總結
總的來看,HULK排程系統的共享狀態資源排程模式與Omega比較相似,不同的是Omega採用MVCC為每個節點維護一個狀態關係資料庫,而HULK使用Actor模型來解決提交衝突。另外,HULK排程任務的n次最優重試機制,在網際網路的彈性伸縮場景下可以帶來更高效的排程能力。
結束語
彈性排程系統作為HULK平臺的核心模組之一,有著下接美團雲IaaS平臺、抽象化資源層,上承彈性伸縮系統、處理排程請求的職責。我們從美團點評的服務特殊性出發,打造適用於大規模容器化場景的排程體系,後續還會在大資料離線任務場景下做更優化的深層智慧排程。
此外,我們對Kubernetes等開源解決方案同樣抱有極大的興趣,從Kubernetes近年來的發展上能看到未來容器平臺的標準雛形,我們也在積極參與和回饋開源社群。
文章來自微信公眾號:Docker