YARN做爲Hadoop的資源管理系統,負責Hadoop集羣上計算資源的管理和做業調度。html
美團的YARN以社區2.7.1版本爲基礎構建分支。目前在YARN上支撐離線業務、實時業務以及機器學習業務。node
YARN面臨高可用、擴展性、穩定性的問題不少。其中擴展性上遇到的最嚴重的,是集羣和業務規模增加帶來的調度器性能問題。從業務角度來看,假設集羣1000臺節點,每一個節點提供100個CPU的計算能力。每一個任務使用1個CPU,平均執行時間1分鐘。集羣在高峯期始終有超過10萬CPU的資源需求。集羣的調度器平均每分鐘只能調度5萬的任務。從分鐘級別觀察,集羣資源使用率是50000/(100*1000)=0.5,那麼集羣就有50%的計算資源由於調度能力的問題而沒法使用。linux
隨着集羣規模擴大以及業務量的增加,集羣調度能力會隨着壓力增長而逐漸降低。假設調度能力依然保持不變,每分鐘調度5萬個任務,按照5000臺節點的規模計算,若是不作任何優化改進,那麼集羣資源使用率爲:50000/(100*5000) = 10%,剩餘的90%的機器資源沒法被利用起來。算法
這個問題解決後,集羣在有空餘資源的狀況下,做業資源需求能夠快速獲得知足,集羣的計算資源獲得充分地利用。apache
下文會逐步將Hadoop YARN調度系統的核心模塊展開說明,揭開上述性能問題的根本緣由,提出系統化的解決方案,最終Hadoop YARN達到支撐單集羣萬級別節點,支持併發運行數萬做業的調度能力。性能優化
YARN負責做業資源調度,在集羣中找到知足業務的資源,幫助做業啓動任務,管理做業的生命週期。bash
YARN詳細的架構設計請參考Hadoop官方文檔。數據結構
YARN在cpu,memory這兩個資源維度對集羣資源作了抽象。多線程
class Resource{
int cpu; //cpu核心個數
int memory-mb; //內存的MB數
}
複製代碼
做業向YARN申請資源的請求是:List[ResourceRequest]架構
class ResourceRequest{
int numContainers; //須要的container個數
Resource capability;//每一個container的資源
}
複製代碼
YARN對做業響應是:List[Container]
class Container{
ContainerId containerId; //YARN全局惟一的container標示
Resource capability; //該container的資源信息
String nodeHttpAddress; //該container能夠啓動的NodeManager的hostname
}
複製代碼
名詞解釋
調度流程
資源申請和分配是異步進行的。ResourceScheduler是抽象類,須要自行實現。社區實現了公平調度器(FairScheduler)和容量調度器(CapacityScheduler)。美團點評根據自身的業務模式的特色,採用的是公平調度器。
在公平調度器中,做業(App)是掛載以下圖的樹形隊列的葉子。
對於每層隊列進行以下流程:
例如,某次調度的路徑是ROOT -> ParentQueueA -> LeafQueueA1 -> App11,此次調度會從node上給App11分配Container。
僞代碼
class FairScheduler{
/* input:NodeId
* output:Resource 表示分配出來的某個app的一個container的資源量
* root 是樹形隊列Queue的根
*/
synchronized Resource attemptScheduling(NodeId node){
root.assignContainer(NodeId);
}
}
class Queue{
Resource assignContainer(NodeId node){
if(! preCheck(node) ) return; //預先檢查
sort(this.children); //排序
if(this.isParent){
for(Queue q: this.children)
q.assignContainer(node); //遞歸調用
}else{
for(App app: this.runnableApps)
app.assignContainer(node);
}
}
}
class App{
Resource assignContainer(NodeId node){
......
}
}
複製代碼
公平調度器是一個多線程異步協做的架構,而爲了保證調度過程當中數據的一致性,在主要的流程中加入了FairScheduler對象鎖。其中核心調度流程是單線程執行的。這意味着Container分配是串行的,這是調度器存在性能瓶頸的核心緣由。
上文介紹了公平調度器的架構,在大規模的業務壓力下,這個系統存在性能問題。從應用層的表現看,做業資源需求得不到知足。從系統模塊看,多個模塊協同工做,每一個模塊多多少少都存在性能問題。如何評估系統性能已經能夠知足線上業務的需求?如何評估系統的業務承載能力?咱們須要找到一個系統的性能目標。所以在談性能優化方案以前,須要先說一說調度系統性能評估方法。
通常來講,在線業務系統的性能是用該系統可以承載的QPS和響應的TP99的延遲時間來評估,而調度系統與在線業務系統不一樣的是:調度系統的性能不能用RPC(ResourceManager接收NodeManager和AppMaster的RPC請求)的響應延遲來評估。緣由是:這些RPC調用過程跟調度系統的調度過程是異步的,所以不論調度性能多麼差,RPC響應幾乎不受影響。同理,不論RPC響應多麼差,調度性能也幾乎不受影響。
首先從知足業務需求角度分析調度系統的業務指標。調度系統的業務目標是知足業務資源需求。指標是:有效調度(validSchedule)。在生產環境,只要validSchedule達標,咱們就認爲目前調度器是知足線上業務需求的。
定義validSchedulePerMin表示某一分鐘的調度性能達標的狀況。達標值爲1,不達標值爲0。
validPending = min(queuePending, QueueMaxQuota)
if (usage / total > 90% || validPending == 0): validSchedulePerMin = 1 //集羣資源使用率高於90%,或者集羣有效資源需求爲0,這時調度器性能達標。
if (validPending > 0 && usage / total < 90%) : validSchedulePerMin = 0;//集羣資源使用率低於90%,而且集羣存在有效資源需求,這時調度器性能不達標。
複製代碼
設置90%的緣由是:資源池中的每一個節點可能都有一小部分資源由於沒法知足任何的資源需求,出現的資源碎片問題。這個問題相似linux內存的碎片問題。因爲離線做業的任務執行時間很是短,資源很快能夠獲得回收。在離線計算場景,調度效率的重要性遠遠大於更精確地管理集羣資源碎片,所以離線調度策略暫時沒有考慮資源碎片的問題。
validSchedulePerDay表示調度性能天天的達標率。 validSchedulePerDay = ΣvalidSchedulePerMin /1440
目前線上業務規模下,業務指標以下: validSchedulePerMin > 0.9; validSchedulePerDay > 0.99
調度系統的本質是爲做業分配Container,所以提出調度系統性能指標CPS--每秒調度Container數。 在生產環境,只要validSchedule達標,代表目前調度器是知足線上業務需求的。而在測試環境,須要關注不一樣壓力條件下的CPS,找到當前系統承載能力的上限,並進一步指導性能優化工做。
CPS是與測試壓力相關的,測試壓力越大,CPS可能越低。從上文公平調度器的架構能夠看到,CPS跟以下信息相關:
例如,集羣1000個節點,同時運行1000個App,這些App分佈在500個Queue上,每一個App的每一個Container執行時間是1分鐘。在這樣的壓力條件下,調度系統在有大量資源需求的狀況下,每秒能夠調度1000個Container。那麼在這個條件下,調度系統的CPS是1000/s。
在線上環境中,咱們能夠經過觀察上文提到的調度系統的指標來看當前調度性能是否知足業務需求。但咱們作了一個性能優化策略,不能直接到在線上環境去實驗,所以咱們必須有能力在線下環境驗證調度器的性能是知足業務需求的,以後才能把實驗有效的優化策略推廣到線上環境。
那咱們在線下也搭建一套跟線上規模同樣的集羣,是否就能夠進行調度器性能優化的分析和研究呢?理論上是能夠的,但這須要大量的物理機資源,對公司來講是個巨大的成本。所以咱們須要一個調度器的壓力模擬器,在不須要大量物理機資源的條件下,可以模擬YARN的調度過程。
社區提供了開源調度器的壓力模擬工具--Scheduler Load Simulater(SLS)。
如上圖,左側是開源SLS的架構圖,總體都在一個進程中,ResourceManager模塊裏面有一個用線程模擬的Scheduler。App和NM(NodeManager)都是由線程模擬。做業資源申請和NM節點心跳採用方法調用。
開源架構存在的問題有:
針對存在的問題,咱們進行了架構改造。右側是改造後的架構圖,從SLS中剝離Scheduler Wapper的模擬邏輯,用真實的ResourceManager代替。SLS僅僅負責模擬做業的資源申請和節點的心跳彙報。ResourceManager是真實的,線上生產環境和線下壓測環境暴露的指標是徹底同樣的,所以線上線下能夠很直觀地進行指標對比。詳細代碼參考:YARN-7672
利用調度壓力模擬器進行壓測,觀察到validSchedule不達標,但依然不清楚性能瓶頸到底在哪裏。所以須要細粒度指標來肯定性能的瓶頸點。因爲調度過程是單線程的,所以細粒度指標獲取的手段是侵入FairScheduler,在調度流程中採集關鍵函數每分鐘的時間消耗。目標是找到花費時間佔比最多的函數,從而定位系統瓶頸。例如:在preCheck函數的先後加入時間統計,就能夠收集到調度過程當中preCheck消耗的時間。
基於以上的思路,咱們定義了10多個細粒度指標,比較關鍵的指標有:
第一次作壓測,給定的壓力就是當時線上生產環境峯值的壓力狀況(1000節點、1000做業併發、500隊列、單Container執行時間40秒)。通過優化後,調度器性能提高,知足業務需求,以後經過預估業務規模增加來調整測試壓力,反覆迭代地進行優化工做。
下圖是性能優化時間線,縱軸爲調度性能CPS。
在覈心調度流程中,第2步是排序子隊列。觀察細粒度指標,能夠很清楚地看到每分鐘調度流程總共用時50秒,其中排序時間佔用了30秒,佔了最大比例,所以首先考慮優化排序時間。
排序自己用的快速排序算法,已經沒有優化空間。進一步分析排序比較函數,發現排序比較函數的時間複雜度很是高。
計算複雜度最高的部分是:須要獲取隊列/做業的資源使用狀況(resourceUsage)。原算法中,每2個隊列進行比較,須要獲取resourceUsage的時候,程序都是現場計算。計算方式是遞歸累加該隊列下全部做業的resourceUsage。這形成了巨大的重複計算量。
優化策略:將現場計算優化爲提早計算。
提早計算算法:當爲某個App分配了一個Container(資源量定義爲containerResource),那麼遞歸調整父隊列的resourceUsage,讓父隊列的resourceUsage += containerResource。當釋放某個App的一個Container,一樣的道理,讓父隊列resourceUsage -= containerResource。 利用提早計算算法,隊列resourceUsage的統計時間複雜度下降到O(1)。
優化效果:排序相關的細粒度指標耗時明顯降低。
紅框中的指標表示每分鐘調度器用來作隊列/做業排序的時間。從圖中能夠看出,通過優化,排序時間從每分鐘30G(30秒)降低到5G(5秒)之內。 詳細代碼參考:YARN-5969
從上圖看,優化排序比較函數後,藍色的線有明顯的增長,從2秒增長到了20秒。這條藍線指標含義是每分鐘調度器跳過沒有資源需求的做業花費的時間。從時間佔比角度來看,目前優化目標是減小這條藍線的時間。
分析代碼發現,全部隊列/做業都會參與調度。但其實不少隊列/做業根本沒有資源需求,並不須要參與調度。所以優化策略是:在排序以前,從隊列的Children中剔除掉沒有資源需求的隊列/做業。
優化效果:這個指標從20秒降低到幾乎能夠忽略不計。詳細代碼參考:YARN-3547
這時,從上圖中能夠明顯看到有一條線呈現上升趨勢,而且這個指標占了整個調度時間的最大比例。這條線對應的指標含義是肯定要調度的做業後,調度器爲這個做業分配出一個Container花費的時間。這部分邏輯平均執行一次的時間在0.02ms之內,而且不會隨着集羣規模、做業規模的增長而增長,所以暫時不作進一步優化。
從核心調度流程能夠看出,分配每個Container,都須要進行隊列的排序。排序的時間會隨着業務規模增長(做業數、隊列數的增長)而線性增長。
架構思考:對於公平調度器來講,排序是爲了實現公平的調度策略,但資源需求是時時刻刻變化的,每次變化,都會引發做業資源使用的不公平。即便分配每個Container時都進行排序,也沒法在整個時間軸上達成公平策略。
例如,集羣有10個cpu,T1時刻,集羣只有一個做業App1在運行,申請了10個cpu,那麼集羣會把這10個cpu都分配給App1。T2時刻(T2 > T1),集羣中新來一個做業App2,這時集羣已經沒有資源了,所以沒法爲App2分配資源。這時集羣中App1和App2對資源的使用是不公平的。從這個例子看,僅僅經過調度的分配算法是沒法在時間軸上實現公平調度。
目前公平調度器的公平策略是保證集羣在某一時刻資源調度的公平。在整個時間軸上是須要搶佔策略來補充達到公平的目標。 所以從時間軸的角度考慮,沒有必要在分配每個Container時都進行排序。
綜上分析,優化策略是排序過程與調度過程並行化。要點以下:
優化效果以下:
隊列排序效率:利用線程池對2000個隊列進行一次排序只須要5毫秒之內(2ms-5ms),在一秒內至少能夠完成200次排序,對業務徹底沒有影響。
在並行運行1萬做業,集羣1.2萬的節點,隊列個數2000,單Container執行時間40秒的壓力下,調度CPS達到5萬,在一分鐘內能夠將整個集羣資源打滿,並持續打滿。
上圖中,15:26分,pending值是0,表示這時集羣目前全部的資源需求已經被調度完成。15:27分,resourceUsage達到1.0,表示集羣資源使用率爲100%,集羣沒有空閒資源。pending值達到4M(400萬 mb的內存需求)是由於沒有空閒資源致使的資源等待。
線下壓測的結果很是好,最終要上到線上才能達成業務目標。然而穩定上線是有難度的,緣由:
除了常規的單元測試、功能測試、壓力測試、設置報警指標以外,咱們根據業務場景提出了針對集羣調度系統的上線策略。
離線生產的業務高峯在凌晨,所以凌晨服務出現故障的機率是最大的。而凌晨RD同窗接到報警電話,執行一般的服務回滾流程(回滾代碼,重啓服務)的效率是很低的。而且重啓期間,服務不可用,對業務產生了更長的不可用時間。所以咱們針對調度器的每一個優化策略都有參數配置。只須要修改參數配置,執行配置更新命令,那麼在不重啓服務的狀況下,就能夠改變調度器的執行邏輯,將執行邏輯切換回優化前的流程。
這裏的關鍵問題是:系統經過配置加載線程更新了調度器某個參數的值,而調度線程也同時在按照這個參數值進行工做。在一次調度過程當中可能屢次查看這個參數的值,而且根據參數值來執行相應的邏輯。調度線程在一次調度過程當中觀察到的參數值發生變化,就會致使系統異常。
處理辦法是經過複製資源的方式,避免多線程共享資源引發數據不一致的問題。調度線程在每次調度開始階段,先將當前全部性能優化參數進行復制,確保在本次調度過程當中觀察到的參數不會變動。
優化算法是爲了提高性能,但要注意不能影響算法的輸出結果,確保算法正確性。對於複雜的算法優化,確保算法正確性是一個頗有難度的工做。
在「優化排序比較時間」的研發中,變動了隊列resourceUsage的計算方法,從現場計算變動爲提早計算。那麼如何保證優化後算法計算出來的resourceUsage是正確的呢?
即便作了單元策略,功能測試,壓力測試,但面對一個複雜系統,依然不能有100%的把握。 另外,將來系統升級也可能引發這部分功能的bug。
算法變動後,若是新的resourceUsage計算錯誤,那麼就會致使調度策略一直錯誤執行下去。從而影響隊列的資源分配。會對業務產生巨大的影響。例如,業務拿不到本來的資源量,致使業務延遲。
經過原先現場計算的方式獲得的全部隊列的resourceUsage必定是正確的,定義爲oldResourceUsage。 算法優化後,經過提早計算的方式獲得全部隊列的resourceUsage,定義爲newResourceUsage。
在系統中,按期對oldResourceUsage和newResourceUsage進行比較,若是發現數據不一致,說明優化的算法有bug,newResourceUsage計算錯誤。這時系統會向RD發送報警通知,同時自動地將全部計算錯誤的數據用正確的數據替換,使得錯誤獲得及時自動修正。
本文主要介紹了美團點評Hadoop YARN集羣公平調度器的性能優化實踐。
單個YARN集羣調度器的性能優化老是有限的,目前咱們能夠支持1萬節點的集羣規模,那麼將來10萬,100萬的節點咱們如何應對?
咱們的解決思路是:基於社區的思路,設計適合美團點評的業務場景的技術方案。社區Hadoop 3.0研發了Global Scheduling,徹底顛覆了目前YARN調度器的架構,能夠極大提升單集羣調度性能。咱們正在跟進這個Feature。社區的YARN Federation已經逐步完善。該架構能夠支撐多個YARN集羣對外提供統一的集羣計算服務,因爲每一個YARN集羣都有本身的調度器,這至關於橫向擴展了調度器的個數,從而提升集羣總體的調度能力。咱們基於社區的架構,結合美團點評的業務場景,正在不斷地完善美團點評的YARN Federation。
世龍、廷穩,美團用戶平臺大數據與算法部研發工程師。
數據平臺資源調度團隊,目標是建設超大規模、高性能、支持異構計算資源和多場景的資源調度系統。目前管理的計算節點接近 3 萬臺,在單集羣節點過萬的規模下實現了單日數十萬離線計算做業的高效調度,資源利用率超過 90%。資源調度系統同時實現了對實時計算做業、機器學習模型 Serving 服務等高可用場景的支持,可用性超過 99.9%。系統也提供了對 CPU/GPU 等異構資源的調度支持,實現了數千張 GPU卡的高效調度,以及 CPU 資源的離線與訓練混合調度,目前正在引入 NPU/FPGA 等更多異構資源,針對機器學習場景的特色實現更高效合理的調度策略。
咱們有多個崗位正在招聘,若是你對超大規模系統的挑戰感到興奮,若是你對異構計算資源的調度策略感到好奇,歡迎加入咱們,聯繫郵箱 sunyerui#meituan.com。