本文從利用率提升、多負(fù)載場景優(yōu)化、穩(wěn)定性提升、異地多活四個(gè)方面介紹了字節(jié)跳動(dòng)在四年來對 Hadoop YARN 進(jìn)行的一系列的優(yōu)化,以及生產(chǎn)環(huán)境中的實(shí)踐經(jīng)驗(yàn)。
1.YARN 簡介
1.1 YARN 生態(tài)圈
YARN (Yet Another Resource Negotiator) 是 Hadoop 集群的資源管理系統(tǒng),是 Hadoop 生態(tài)中非常重要的成員項(xiàng)目。
一般來說,離線生態(tài)可以分為五層:
- 最底層是裸金屬層, 由眾多物理節(jié)點(diǎn)組成,每個(gè)節(jié)點(diǎn)上運(yùn)行著通用的操作系統(tǒng)。
- 次底層是集群資源管理層, YARN 就處在這一層中。
- 再往上是分布式計(jì)算引擎層, MR/Spark/Flink 等計(jì)算引擎處于這層,為了能讓業(yè)務(wù)同學(xué)更加低成本的寫計(jì)算任務(wù), 各個(gè)引擎都支持 SQL 功能。
- 再往上是作業(yè)托管層,用來提交 ad-hoc 的作業(yè),管理周期性的批處理作業(yè),管理長時(shí)間運(yùn)行的流式作業(yè)。
- 最上層是用戶邏輯層,如數(shù)據(jù)日報(bào),數(shù)據(jù)分析,模型訓(xùn)練等.
1.2 YARN 架構(gòu)
上圖中灰色背景區(qū)域是 YARN 的主要架構(gòu), 主要包含兩種角色:
- ResourceManager整個(gè)集群的大腦,負(fù)責(zé)為應(yīng)用調(diào)度資源,管理應(yīng)用生命周期。對用戶提供接口,包括命令行接口,API, WebUI 接口。可以同時(shí)存在多個(gè) RM,但同一時(shí)間只有一個(gè)在工作,RM 之間通過 ZK 選主。
- NodeManager為整個(gè)集群提供資源,接受 Container 運(yùn)行。管理 Contianer 的運(yùn)行時(shí)生命周期,包括 Localization,資源隔離,日志聚合等。
YARN 上運(yùn)行的作業(yè):
- 在運(yùn)行時(shí)會(huì)訪問外部的數(shù)據(jù)服務(wù),常見的如 HDFS,Kafka 等
- 會(huì)在運(yùn)行結(jié)束后由 YARN 負(fù)責(zé)將日志上傳到 HDFS 中
2.字節(jié)跳動(dòng)對 YARN 的定制
字節(jié)跳動(dòng)的 YARN 是在 16 年從社區(qū)當(dāng)時(shí)最新的 2.6.0 版本中 fork 出來的,主要承載著公司內(nèi)的離線作業(yè)/流式作業(yè)/模型訓(xùn)練三大場景。 由于公司內(nèi)的 YARN 服務(wù)規(guī)模巨大、場景復(fù)雜,遇到了各種問題,在社區(qū)版本沒有提供解決方案之前,內(nèi)部研發(fā)同學(xué)定制了許多內(nèi)容來解決具體問題,經(jīng)過 4 年來上千次的修改,公司內(nèi)的版本已經(jīng)跟社區(qū)的版本相差較大。
今天給大家介紹一些比較關(guān)鍵的定制,希望能給大家?guī)硪恍﹩l(fā)。這些關(guān)鍵定制主要包括四個(gè)方面:
- 利用率提升: 包括分配率提升和物理使用率提升。
- 多種負(fù)載場景優(yōu)化: 包括批處理 / 流式 / 模型訓(xùn)練 三種場景下的體驗(yàn)提升。
- 穩(wěn)定性提升: 包括擺脫對 HDFS 強(qiáng)依賴, Container 分級與驅(qū)逐, 非受控 Container 管理。
- 異地多活: 包括統(tǒng)一的 YARN Client 和 UI 等內(nèi)容。
2.1 利用率提升
2.1.1 多線程版本的 Fair Scheduler
社區(qū)原生版本的 FairScheduler 是單線程的,在節(jié)點(diǎn)數(shù)量較多時(shí),是整體集群最大的瓶頸.
我們通過將 FairScheduler 改造為并發(fā)的多線程版本,并將調(diào)度器內(nèi)部的鎖拆分為更加細(xì)粒度的讀鎖和寫鎖,將調(diào)度吞吐提升 7 倍以上,在生產(chǎn)環(huán)境中達(dá)到每秒 3K 個(gè) Container 的速度(未觸及性能瓶頸)。
2.1.2 考慮節(jié)點(diǎn) DRF 的調(diào)度
原生的 YARN 在調(diào)度時(shí)只考慮資源是否滿足,經(jīng)常會(huì)出現(xiàn)一個(gè)節(jié)點(diǎn) CPU 被打滿,但是內(nèi)存還有剩余的情況。
我們引入節(jié)點(diǎn) DRF(Dominant Resource Fairness)機(jī)制,計(jì)算每個(gè)節(jié)點(diǎn)的剩余資源的主資源,當(dāng)調(diào)度的 Task 的主資源與節(jié)點(diǎn)的主資源不匹配時(shí),先延遲此次調(diào)度,直到一定次數(shù)后再放松約束。
通過引入這個(gè)機(jī)制,集群資源的碎片化問題大幅降低,生產(chǎn)環(huán)境中可以達(dá)到 CPU 和內(nèi)存的 24 小時(shí)平均利用率都在 90%以上。
2.1.3 提升單集群規(guī)模
單個(gè)集群的規(guī)模越大,就可以有更多的用戶和作業(yè)使用這個(gè)集群,這個(gè)集群的利用率也會(huì)更高。但是原生的 YARN 在達(dá)到 5K 節(jié)點(diǎn)規(guī)模時(shí)開始出現(xiàn)各種問題,比如說一次簡單的切主可能會(huì)導(dǎo)致整個(gè)集群雪崩。
我們?yōu)樘嵘龁渭阂?guī)模做了一系列的優(yōu)化。
- 首先,通過對 YARN 內(nèi)部事件梳理調(diào)整,精準(zhǔn)的修改了一些事件處理邏輯。
- 然后,將 NodeManager 節(jié)點(diǎn)的心跳機(jī)制改為根據(jù) ResourceManager 的壓力動(dòng)態(tài)調(diào)整。
- 之后,修改內(nèi)存單位(int->long)突破單個(gè)集群 21 億 MB 的限制
- 再之后,通過對切主過程進(jìn)行深度優(yōu)化, 將切主時(shí)間控制在秒級
當(dāng)然還有很多其它的細(xì)節(jié)優(yōu)化不再一一列舉,最終的效果是讓單個(gè)生產(chǎn)集群達(dá)到了 2 萬節(jié)點(diǎn)的規(guī)模。
2.1.4 與流式&在線服務(wù)混部
公司內(nèi)離線的資源全天都比較緊張,而流式作業(yè)和在線服務(wù)的資源使用量隨著用戶的行為,在時(shí)間上有明顯的波峰波谷,在凌晨時(shí)通過混部的方式將流式和在線富余的資源提供給離線可以全面的提升利用率。
我們通過將 NodeManager 改造為可以根據(jù)宿主機(jī)的富余資源動(dòng)態(tài)的調(diào)整的 NM',來達(dá)到與流式作業(yè)和在線服務(wù)的混部,為離線提供更多資源的目的。
目前生產(chǎn)環(huán)境中已有數(shù)萬臺節(jié)點(diǎn)進(jìn)行了混部,混部后將原機(jī)器的 CPU 利用率絕對值提升了 20%以上。
2.1.5 Smart Resource : 在運(yùn)行時(shí)/重啟時(shí)調(diào)整資源
原生的 YARN 中,用戶申請的資源和實(shí)際使用的資源經(jīng)常會(huì)出現(xiàn)比較大的偏差, 導(dǎo)致出現(xiàn)大量的資源浪費(fèi)的情況,為此我們開發(fā)了一整套的資源動(dòng)態(tài)調(diào)整方案,可以將申請的資源調(diào)整到接近于實(shí)際使用資源的數(shù)值。
并且,在實(shí)際使用中發(fā)現(xiàn),如果資源調(diào)整必須以一個(gè)核為最小粒度的話,還是會(huì)出現(xiàn)很嚴(yán)重的浪費(fèi),比如用戶真實(shí)的需求可能是 0.001 個(gè)核*1000,原生的 YARN 只能分配 1000 個(gè)核,就白白浪費(fèi)了 999 個(gè)核。我們開發(fā)了以千分之一核為最小粒度的功能,可以有效的減少資源的浪費(fèi)。并且千分之一核與資源動(dòng)態(tài)調(diào)整結(jié)合,可以更加精細(xì)化的調(diào)整資源。
2.2 多種負(fù)載場景優(yōu)化
字節(jié)跳動(dòng)的 YARN 承載了公司內(nèi)的 批處理 / 流式 / 模型訓(xùn)練 三大場景,由于 YARN 天生是為批處理而設(shè)計(jì)的,很多地方與流式 / 模型訓(xùn)練場景并不匹配,為了給這些場景更好的體驗(yàn),需要做一些定制工作。
2.2.1 YARN Gang Scheduler 調(diào)度器
流式作業(yè)和訓(xùn)練作業(yè)的調(diào)度需求與批處理有很大的不同:批處理強(qiáng)調(diào)的是高吞吐,而流式/訓(xùn)練類型的作業(yè)更加強(qiáng)調(diào)低延遲和全局視角。為了彌補(bǔ)原生 YARN 在低延遲和全局視角上的缺陷,我們開發(fā)了一個(gè)全新的調(diào)度器 Gang Scheduler。
Gang Scheduler 提供了一個(gè) All-or-Nothing (一次全交付或不交付)的語義,如作業(yè)申請 1000 個(gè) container,那么要么直接返回 1000 個(gè) container,要么就返回失敗,并提示失敗的原因。這樣可以有效的避免兩個(gè)作業(yè)都只拿到一半的資源,誰也無法啟動(dòng)的互鎖局面。
除此之外,Gang Scheduler 還有個(gè)特性是超低延遲, 它可以在毫秒級給出 All-or-Nothing 的結(jié)論,這樣可以大大緩解流式作業(yè)在重啟時(shí)的 lag 積壓問題。
最重要的是,Gang Scheduler 為流式作業(yè)和訓(xùn)練作業(yè)提供了全局視角,每個(gè)作業(yè)可以通過配置自己定制的強(qiáng)約束和弱約束來達(dá)到全局最優(yōu)的放置策略。其中,強(qiáng)約束是指必須要滿足的條件;弱約束是指盡量滿足,但確實(shí)無法滿足時(shí)可以接受降級的約束。目前支持的強(qiáng)約束包括節(jié)點(diǎn)屬性, 高負(fù)載等;支持的弱約束包括:節(jié)點(diǎn)屬性,高負(fù)載,Container 打散,Quota 平均,GPU 親和性等。
2.2.2 更加精細(xì)化的 CPU 使用策略
除了開啟 YANR 原生默認(rèn)支持的 CGroup 限制之外,我們還配置了更加豐富的 CGroup 管理策略,比如在 share 模式下支持自定義的最大值限制,支持綁核,支持綁 NUMA 節(jié)點(diǎn)等. 通過這些措施,給流式作業(yè)和訓(xùn)練作業(yè)更加靈活的管控策略,滿足不同場景下的隔離或共享需求。
2.2.3 訓(xùn)練場景下的其它定制
對于訓(xùn)練場景,我們還定制了更豐富的內(nèi)容。包括:
- 為了更好的隔離性,定制了支持 GPU 和 Ceph 的 Docker
- 為了更靈活的資源申請,定制了帶范圍的資源值 (傳統(tǒng)的 YARN 資源只有個(gè)數(shù), 沒有范圍,比如多少個(gè) CPU,多少 GB 內(nèi)存,但在訓(xùn)練場景下,有時(shí)希望有范圍,比如當(dāng)需要兩個(gè) GPU 卡時(shí),不止希望隨意的兩張卡,而是希望要一臺機(jī)器上兩個(gè)連號的 GPU 卡,比如卡 0 和卡 1 是連號的,而卡 0 和卡 2 不是連號的。這個(gè)場景同樣也適用于端口號。)
- 為了更高效的同時(shí)使用 CPU 和 GPU 機(jī)器,定制了節(jié)點(diǎn)屬性功能。
2.2.4 跳過高 Load 節(jié)點(diǎn)
離線批處理場景經(jīng)常會(huì)遇到"Fetch Failed"的問題,主要來源是本地的磁盤 IOPS 不足,導(dǎo)致 Shuffle Service 卡住,為了緩解這個(gè)問題,我們在資源調(diào)度的過程中加入目標(biāo)主機(jī) LoadAvg 的考慮因素,如果一臺機(jī)器的 LoadAvg 過高,則暫時(shí)跳過對其分配新任務(wù). 通過這個(gè)機(jī)制,將"Fetch Failed"問題降低了約 40%。
2.3 穩(wěn)定性優(yōu)化
字節(jié)跳動(dòng)的 YARN 服務(wù)規(guī)模巨大,在穩(wěn)定性方面遇到了很多挑戰(zhàn),有很多細(xì)節(jié)方面的優(yōu)化, 在這里由于時(shí)間有限,挑選幾個(gè)比較有代表性的優(yōu)化點(diǎn)跟大家分享一下:
- 將 HDFS 做成弱依賴對于一般的離線批處理來說,如果 HDFS 服務(wù)不可用了,那么 YARN 也沒必要繼續(xù)運(yùn)行了。但是在字節(jié)跳動(dòng)內(nèi)部由于 YARN 還同時(shí)承載流式作業(yè)和模型訓(xùn)練,因此不能容忍 HDFS 故障影響到 YARN。為此,我們通過將 NodeLabel 存儲到 ZK 中,將 Container Log 在 HDFS 的目錄初始化和上傳都改為異步的方式,擺脫了對 HDFS 的強(qiáng)依賴。
- Container 分級與驅(qū)逐某些 Container 的磁盤空間占用過高,或者將單機(jī) Load 打得非常高,會(huì)比較嚴(yán)重的影響到其它 Container 的正常運(yùn)行,為此,我們?yōu)?YARN 定制了 Container 分級與驅(qū)逐機(jī)制。對于可能會(huì)嚴(yán)重影響到其它 Container 的 Container 會(huì)進(jìn)行主動(dòng)驅(qū)逐。對于被驅(qū)逐的作業(yè),可申請到獨(dú)立的 Label 中運(yùn)行。
- 非受控 Container 的清理機(jī)制由于種種原因,線上總是會(huì)出現(xiàn)一些 Container 明明還在運(yùn)行,但是已經(jīng)不受 YARN 的管控。通常是由于不正常的運(yùn)維操作產(chǎn)生,或者機(jī)器本身出現(xiàn)故障導(dǎo)致。對于這些 Container 如果不加管制,不僅會(huì)讓單機(jī)的實(shí)際資源緊張,有時(shí)還會(huì)造成 Kafka Topic 的重復(fù)消費(fèi)導(dǎo)致線上事故。為此我們在 YARN 的 NodeManager 中增加了非受控 Container 的清理機(jī)制。
2.4 異地多活
隨著公司發(fā)展迅猛,YARN 也迎來了異地多機(jī)房的場景,原生的 YARN 只支持單集群使用, 對用戶的使用造成不便,如果每個(gè)集群都孤立的提供給用戶的話,會(huì)讓用戶使用起來很困難,為此,我們對異地多活做了一些定制工作:
- 全球統(tǒng)一的 YARN UI 界面為所有的 YARN 用戶統(tǒng)一定制了一個(gè) YARN UI 界面,該界面包含全球的所有隊(duì)列和用戶的作業(yè)。
- 放棄數(shù)據(jù)本地性調(diào)度延遲等待當(dāng)有多個(gè)集群時(shí),很難與 HDFS 的數(shù)據(jù)進(jìn)行本地性對齊。機(jī)房內(nèi)網(wǎng)絡(luò)資源富余,數(shù)據(jù)本地性對性能提升不明顯,還會(huì)導(dǎo)致集群吞吐下降。
- YARN 安全模式為了配合多機(jī)房容災(zāi),有時(shí)需要主動(dòng)將部分 YARN 集群設(shè)置為不調(diào)度新任務(wù)的安全模式。
3. 未來工作
未來我們會(huì)持續(xù)的優(yōu)化與流式和在線服務(wù)的混部工作,包括:
- 物理利用率提升
- 更好的隔離
- 更加可控的殺死率
- GPU 資源的混部
同時(shí),我們也會(huì)繼續(xù)完善 YARN Gang Scheduler,包括:
- 更加豐富的調(diào)度謂詞
- 更加低延遲
4. 團(tuán)隊(duì)介紹
基礎(chǔ)架構(gòu) YARN 團(tuán)隊(duì)負(fù)責(zé)字節(jié)跳動(dòng)公司內(nèi)部離線/流式/模型訓(xùn)練三大場景的資源管理和調(diào)度, 支撐了推薦/數(shù)倉/搜索/廣告等眾多核心業(yè)務(wù),管理著在集群規(guī)模、調(diào)度吞吐能力、資源利用率、業(yè)務(wù)復(fù)雜性等多個(gè)方向上都在業(yè)界領(lǐng)先的超大規(guī)模集群。
針對公司內(nèi)的抖音、今日頭條等產(chǎn)品重度依賴推薦的特點(diǎn), 團(tuán)隊(duì)對調(diào)度器進(jìn)行了深度定制以支持流式(Flink)訓(xùn)練和 GPU 訓(xùn)練等場景, 擁有幾十項(xiàng)專利技術(shù)。同時(shí)為了進(jìn)一步提升集群資源利用率,調(diào)度團(tuán)隊(duì)已經(jīng)開啟在離線大規(guī)模混部,并且預(yù)期在不久后會(huì)進(jìn)一步融合 YARN / K8S 等調(diào)度系統(tǒng)。
業(yè)務(wù)擴(kuò)張,團(tuán)隊(duì)長期在北京/杭州招人。簡歷投遞入口: https://job.toutiao.com/s/KcoXsV
歡迎關(guān)注字節(jié)跳動(dòng)技術(shù)團(tuán)隊(duì)