您好,登錄后才能下訂單哦!
YARN作為Hadoop的資源管理系統,負責Hadoop集群上計算資源的管理和作業調度。
美團的YARN以社區2.7.1版本為基礎構建分支。目前在YARN上支撐離線業務、實時業務以及機器學習業務。
離線業務主要運行的是Hive on MapReduce, Spark SQL為主的數據倉庫作業。
實時業務主要運行Spark Streaming,Flink為主的實時流計算作業。
機器學習業務主要運行TensorFlow,MXNet,MLX(美團點評自研的大規模機器學習系統)等計算作業。
YARN面臨高可用、擴展性、穩定性的問題很多。其中擴展性上遇到的最嚴重的,是集群和業務規模增長帶來的調度器性能問題。從業務角度來看,假設集群1000臺節點,每個節點提供100個CPU的計算能力。每個任務使用1個CPU,平均執行時間1分鐘。集群在高峰期始終有超過10萬CPU的資源需求。集群的調度器平均每分鐘只能調度5萬的任務。從分鐘級別觀察,集群資源使用率是50000/(100*1000)=0.5,那么集群就有50%的計算資源因為調度能力的問題而無法使用。
隨著集群規模擴大以及業務量的增長,集群調度能力會隨著壓力增加而逐漸下降。假設調度能力依然保持不變,每分鐘調度5萬個任務,按照5000臺節點的規模計算,如果不做任何優化改進,那么集群資源使用率為:50000/(100*5000) = 10%,剩余的90%的機器資源無法被利用起來。
這個問題解決后,集群在有空余資源的情況下,作業資源需求可以快速得到滿足,集群的計算資源得到充分地利用。
下文會逐步將Hadoop YARN調度系統的核心模塊展開說明,揭開上述性能問題的根本原因,提出系統化的解決方案,最終Hadoop YARN達到支撐單集群萬級別節點,支持并發運行數萬作業的調度能力。
YARN負責作業資源調度,在集群中找到滿足業務的資源,幫助作業啟動任務,管理作業的生命周期。
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}
cdn.xitu.io/2019/8/5/16c5facf148d4676?w=950&h=568&f=png&s=123418">
名詞解釋
ResourceScheduler是YARN的調度器,負責Container的分配。
AsyncDispatcher是單線程的事件分發器,負責向調度器發送調度事件。
ResourceTrackerService是資源跟蹤服務,主要負責接收處理NodeManager的心跳信息。
ApplicationMasterService是作業的RPC服務,主要負責接收處理作業的心跳信息。
AppMaster是作業的程序控制器,負責跟YARN交互獲取/釋放資源。
調度流程
作業資源申請過程:AppMaster通過心跳告知YARN資源需求(List[ResourceRequest]),并取回上次心跳之后,調度器已經分配好的資源(List[Container])。
調度器分配資源流程是:Nodemanager心跳觸發調度器為該NodeManager分配Container。
資源申請和分配是異步進行的。ResourceScheduler是抽象類,需要自行實現。社區實現了公平調度器(FairScheduler)和容量調度器(CapacityScheduler)。美團點評根據自身的業務模式的特點,采用的是公平調度器。
在公平調度器中,作業(App)是掛載如下圖的樹形隊列的葉子。?
調度器鎖住FairScheduler對象,避免核心數據結構沖突。
調度器選取集群的一個節點(node),從樹形隊列的根節點ROOT開始出發,每層隊列都會按照公平策略選擇一個子隊列,最后在葉子隊列按照公平策略選擇一個App,為這個App在node上找一塊適配的資源。
對于每層隊列進行如下流程:
隊列預先檢查:檢查隊列的資源使用量是否已經超過了隊列的Quota
排序子隊列/App:按照公平調度策略,對子隊列/App進行排序
遞歸調度子隊列/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分配是串行的,這是調度器存在性能瓶頸的核心原因。
scheduler Lock:FairScheduler對象鎖
AllocationFileLoaderService:負責公平策略配置文件的熱加載,更新隊列數據結構
Continuous Scheduling Thread:核心調度線程,不停地執行上節的核心調度流程
Update Thread:更新隊列資源需求,執行Container搶占流程等
Scheduler Event Dispatcher Thread: 調度器事件的處理器,處理App新增,App結束,node新增,node移除等事件
上文介紹了公平調度器的架構,在大規模的業務壓力下,這個系統存在性能問題。從應用層的表現看,作業資源需求得不到滿足。從系統模塊看,多個模塊協同工作,每個模塊多多少少都存在性能問題。如何評估系統性能已經可以滿足線上業務的需求?如何評估系統的業務承載能力?我們需要找到一個系統的性能目標。因此在談性能優化方案之前,需要先說一說調度系統性能評估方法。
一般來說,在線業務系統的性能是用該系統能夠承載的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%,并且集群存在有效資源需求,這時調度器性能不達標。
validPending表示集群中作業有效的資源需求量
queuePending表示隊列中所有作業的資源需求量
QueueMaxQuota表示該隊列資源最大限額
usage表示集群已經使用的資源量
tatal表示集群總體資源
設置90%的原因是:資源池中的每個節點可能都有一小部分資源因為無法滿足任何的資源需求,出現的資源碎片問題。這個問題類似linux內存的碎片問題。由于離線作業的任務執行時間非常短,資源很快可以得到回收。在離線計算場景,調度效率的重要性遠遠大于更精確地管理集群資源碎片,因此離線調度策略暫時沒有考慮資源碎片的問題。
validSchedulePerDay表示調度性能每天的達標率。?validSchedulePerDay = ΣvalidSchedulePerMin /1440
目前線上業務規模下,業務指標如下:?validSchedulePerMin > 0.9; validSchedulePerDay > 0.99
調度系統的本質是為作業分配Container,因此提出調度系統性能指標CPS--每秒調度Container數。 在生產環境,只要validSchedule達標,表明目前調度器是滿足線上業務需求的。而在測試環境,需要關注不同壓力條件下的CPS,找到當前系統承載能力的上限,并進一步指導性能優化工作。
CPS是與測試壓力相關的,測試壓力越大,CPS可能越低。從上文公平調度器的架構可以看到,CPS跟如下信息相關:
集群總體資源數;集群資源越多,集群可以并發運行的的Container越多,對調度系統產生越大的調度壓力。目前每臺物理機的cpu、memory資源量差距不大,因此集群總體資源數主要看集群的物理機節點個數。
集群中正在運行的App數;作業數越多,需要調度的信息越多,調度壓力越大。
集群中的隊列個數;隊列數越多,需要調度的信息越多,調度壓力越大。
集群中每個任務的執行時間;任務執行時間越短會導致資源釋放越快,那么動態產生的空閑資源越多,對調度系統產生的壓力越大。
例如,集群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節點心跳采用方法調用。
開源架構存在的問題有:
模擬大規模APP和NM需要開啟大量的線程,導致調度器線程和NM/App的模擬線程爭搶cpu資源,影響調度器的評估。
SLS的Scheduler Wapper中加入了不合理的邏輯,嚴重影響調度器的性能。
SLS為了通用性考慮,沒有侵入FairScheduler的調度過程獲取性能指標,僅僅從外圍獲取了Queue資源需求,Queue資源使用量,App資源需求,App資源使用量等指標。這些指標都不是性能指標,無法利用這些指標分析系統性能瓶頸。
針對存在的問題,我們進行了架構改造。右側是改造后的架構圖,從SLS中剝離Scheduler Wapper的模擬邏輯,用真實的ResourceManager代替。SLS僅僅負責模擬作業的資源申請和節點的心跳匯報。ResourceManager是真實的,線上生產環境和線下壓測環境暴露的指標是完全一樣的,因此線上線下可以很直觀地進行指標對比。詳細代碼參考:YARN-7672
利用調度壓力模擬器進行壓測,觀察到validSchedule不達標,但依然不清楚性能瓶頸到底在哪里。因此需要細粒度指標來確定性能的瓶頸點。由于調度過程是單線程的,因此細粒度指標獲取的手段是侵入FairScheduler,在調度流程中采集關鍵函數每分鐘的時間消耗。目標是找到花費時間占比最多的函數,從而定位系統瓶頸。例如:在preCheck函數的前后加入時間統計,就可以收集到調度過程中preCheck消耗的時間。
基于以上的思路,我們定義了10多個細粒度指標,比較關鍵的指標有:
每分鐘父隊列preCheck時間
每分鐘父隊列排序時間
每分鐘子隊列preCheck時間
每分鐘子隊列排序時間
每分鐘為作業分配資源的時間
每分鐘因為作業無資源需求而花費的時間
第一次做壓測,給定的壓力就是當時線上生產環境峰值的壓力情況(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時都進行排序,也無法在整個時間軸上達成公平策略。鄭州不孕不育醫院哪家好:http://yyk.39.net/zz3/zonghe/1d427.html
例如,集群有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的內存需求)是因為沒有空閑資源導致的資源等待。
線下壓測的結果非常好,最終要上到線上才能達成業務目標。然而穩定上線是有難度的,原因:
線上環境和線下壓測環境中的業務差別非常大。線下沒問題,上線不一定沒問題。
當時YARN集群只有一個,那么調度器也只有一個,如果調度器出現異常,是整個集群的災難,導致整個集群不可用。
除了常規的單元測試、功能測試、壓力測試、設置報警指標之外,我們根據業務場景提出了針對集群調度系統的上線策略。
離線生產的業務高峰在凌晨,因此凌晨服務出現故障的概率是最大的。而凌晨RD同學接到報警電話,執行通常的服務回滾流程(回滾代碼,重啟服務)的效率是很低的。并且重啟期間,服務不可用,對業務產生了更長的不可用時間。因此我們針對調度器的每個優化策略都有參數配置。只需要修改參數配置,執行配置更新命令,那么在不重啟服務的情況下,就可以改變調度器的執行邏輯,將執行邏輯切換回優化前的流程。焦作國醫胃腸醫院正規嗎:http://jz.lieju.com/zhuankeyiyuan/37756433.htm
這里的關鍵問題是:系統通過配置加載線程更新了調度器某個參數的值,而調度線程也同時在按照這個參數值進行工作。在一次調度過程中可能多次查看這個參數的值,并且根據參數值來執行相應的邏輯。調度線程在一次調度過程中觀察到的參數值發生變化,就會導致系統異常。
處理辦法是通過復制資源的方式,避免多線程共享資源引起數據不一致的問題。調度線程在每次調度開始階段,先將當前所有性能優化參數進行復制,確保在本次調度過程中觀察到的參數不會變更。
優化算法是為了提升性能,但要注意不能影響算法的輸出結果,確保算法正確性。對于復雜的算法優化,確保算法正確性是一個很有難度的工作。
在“優化排序比較時間”的研發中,變更了隊列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 萬臺,在單集
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。