OPPO大資料離線計算平臺架構演進

語言: CN / TW / HK

1 前言

OPPO的大資料離線計算髮展,經歷了哪些階段?在生產中遇到哪些 經典的大資料問題?我們是怎麼解決的,從中有哪些架構上的升級演進?未來的OPPO離線平臺有哪些方向規劃?今天會給大家一一揭祕。

OPPO大資料離線計算髮展歷史

2.1 大資料行業發展階段

一家公司的技術發展,離不開整個行業的發展背景。我們簡短迴歸一下大資料行業的發展,通過谷歌的BigData搜尋熱度我們大概分一下大資料的近十幾年的程序。

圖1:google bigdata 關鍵詞搜尋熱度

上面的熱度曲線來看,大資料發展大概可以分成三個階段:

成長期 (2009-2015),這段時期主要代表是Hadoop1.0以及相關生態的快速成長;

巔峰期 (2015-2018),這段時期主要代表是Hadoop2.0以及Spark迅速成為大資料基礎架構和計算引擎的行業事實基礎底座;

成熟期 (2018-now),這段時間主要代表是Spark、Flink等計算引擎以及OLAP引擎的繁榮;

從這個熱度曲線看,有一個小疑問,近兩年大資料熱度迅速下降,那麼什麼技術在近幾年成為熱度最大的技術?

2.2 OPPO 大資料發展階段

OPPO大資料起步比整個行業稍晚,我們先看一下發展時間軸:

2013年,大資料巔峰期之初,OPPO開始搭建大資料叢集和團隊,使用Hadoop 0.20版本(Hadoop1.0)。

2015年,使用CDH服務,叢集初具規模。

2018年,自建叢集,已經達到中等規模,使用Hive作為計算引擎。

2020年,開始大規模從Hive向Spark計算引擎遷移SQL作業。

2021年,從大資料資源層和計算層升級改造。

OPPO的大資料發展可以總結成兩個階段:

發展期 :2013-2018年,OPPO大資料從無到有,慢慢成長,計算節點規模從0擴充套件到中等規模;

繁榮期 :2018-現在,三年大資料快速發展,技術上從hadoop1.0升級到hadoop2.0,計算引擎由hive升級到spark;自研技術以及架構升級解決叢集規模膨脹後常見問題;

3 大資料計算領域常見問題

大資料領域有很多經典的問題,我們這裡選取了生產環境遇到五種典型的問題來說明;我們將圍繞這五種問題展開,介紹OPPO大資料離線計算的架構演進。

圖3:大資料計算領域常見問題

3.1 Shuffle問題

Shuffle是大資料計算的關鍵一環,shuffle 對任務的效能和穩定性都產生重要的影響。有以下幾點因素,導致shuffle效能變慢和穩定性變差:

spill&merge :多次磁碟io;map在寫shuffle資料的過程中,會將記憶體的資料按照一定大小刷到磁碟,最後做sort和merge,會產生多次磁碟io.

磁碟隨機讀 :每個reduce只讀取每個map輸出的部分資料,導致在map端磁碟隨機讀。

過多的RPC連線 :假設有M個map,N個reduce,shuffle過程要建立MxN個RPC連線(考慮多個map可能在同一臺機器,這個MxN是最大連線數)。

Shuffle問題不僅會影響任務的效能和穩定性,同時在大資料任務上雲的過程中,shuffle資料的承接也成為上雲的阻礙。雲上資源的動態回收,需要等待下游讀取上游的shuffle資料之後才能安全的釋放資源,否則會導致shuffle失敗。

3.2 小檔案問題

小檔案問題幾乎是大資料平臺必須面對的問題,小檔案主要有兩點危害:

1)小檔案過多對HDFS儲存的NameNode節點產生比較大的壓力。

2)小檔案過多,會對下游任務併發度產生影響,每個小檔案生成一個map任務讀資料,造成過多的任務生成,同時會有過多的碎片讀。

小檔案問題產生的原因有哪些?

1)任務資料量小同時寫入的併發又比較大,比較典型的場景是動態分割槽。

2)資料傾斜,資料總量可能比較大,但是有資料傾斜,只有部分檔案比較大,其他的檔案都比較小。

3.3 多叢集資源協調問題

隨著業務發展,叢集迅速擴張,單個叢集的規模越來越大,同時,叢集數量也擴充套件到多個。面對多叢集的環境如何做好資源協調是我們面臨的一個挑戰。

首先看下多叢集的優劣勢:

優勢:各個叢集資源隔離,風險隔離,部分業務獨享資源。

劣勢:資源隔離,形成資源孤島,失去大叢集優勢,資源利用率不均勻。

例如, 對比我們線上叢集 vcore資源使用情況:

圖4: 叢集1 24小時資源使用情況

圖5: 叢集2 24小時資源使用情況

從資源使用情況看,叢集2的資源利用率明顯低於叢集1,這就造成叢集之間負載不均勻,資源利用率低下,資源浪費。

3.4 元資料擴充套件問題

由於歷史原因,元資料在叢集搭建初期選取單個MySQL例項儲存。隨著業務資料快速增長的同時,元資料也在飛快增長。這種單點的元資料儲存,已經成為整個大資料系統的穩定性和效能的最大的隱患。同時,在過去的一年,我們的叢集因為元資料服務問題,曾經出現兩次比較大的故障。在此背景下,對元資料的擴充套件,成為緊急且重要的事項。

問題來了,選擇什麼樣的擴充套件方案?

調研業界的幾種方案,包括:

1)使用TiDB等分散式資料庫;

2)從新規劃元資料的分佈,拆分到不同的MySQL;

3)使用Waggle-Dance作為元資料的路由層;

在選型的過程中,我們考慮儘可能對使用者影響最小,做到對使用者透明,平滑擴充套件;

3.5  計算統一入口

在我們將sql任務從hive遷移到spark引擎的同時,我們遇到的首要問題是:SparkSQL 任務能不能像HiveSQL一樣很方便的通過beeline或者jdbc提交?原生的spark是通過spark自帶的submit指令碼提交任務,這種方式顯然不適合大規模生產應用。

所以,我們提出統一計算入口的目標。

不僅統一SparkSQL任務提交,同時 jar包任務也要統一起來。

以上五個問題是我們在生產環境不斷的碰壁,不斷的探索,總結出來的典型的問題。當然,大資料計算領域還有更多的典型問題,限於文章篇幅,這裡僅針對這五個問題探討。

4 OPPO離線計算平臺解決之道

針對前面提到的五個問題,我們介紹一下OPPO的解決方案,同時也是我們的離線計算平臺的架構演進歷程。

4.1 OPPO Remote Shuffle Service

為了解決shuffle的效能和穩定性問題,同時,為大資料任務上雲做鋪墊,我們自研了 OPPO Remote Shuffle  Service(ORS2)。

4.1.1 ORS2在大資料平臺整體架構

圖6:ORS2在雲數融合架構圖

有了ORS2,不僅將spark任務的shuffle過程從本地磁碟解耦,同時承接了雲上資源的大資料計算任務的shuffle資料。

從ShuffleService本身來說,獨立出來一個service角色,負責整合計算任務的shuffle資料。同時,ShuffleService本身可以部署到雲上資源,動態擴縮容,將shuffle資源化。整體架構上看,ShuffleService 分成兩層,上面Service層,主要有ShuffleMaster和ShuffleWorker兩種角色。

ShuffleMaster負責ShuffleWorker的管理,監控,分配。ShuffleWorker將自身的相關資訊上報給ShuffleMaster,master對worker的健康做管理;提供worker加黑放黑、punish等管理操作。分配策略可定製,比如:Random策略、Roundrobin策略、LoadBalance策略。

ShuffleWorker負責彙集資料,將相同分割槽的資料寫入到一個檔案,Reduce讀分割槽資料的過程變成順序讀,避免了隨機讀以及MxN次的RPC通訊。

在儲存層,我們的ShuffleService可以靈活選取不同的分散式儲存檔案系統,分割槽檔案的管理以及穩定性保障交由分散式檔案系統保障。目前支援HDFS、CFS、Alluxio三種分散式檔案系統介面。可以根據不同的需求使用不同的儲存介質,例如,小任務作業或者對效能要求比較高的作業,可以考慮使用記憶體shuffle;對於穩定性要求比較高,作業重要性也比較高的作業,可以選取ssd;對效能要求不高的低級別作業,可以選取SATA儲存;在效能和成本之間尋求最佳的平衡。

4.1.2 ORS2的核心架構

圖7:ORS2 核心架構圖

從ShuffleService的核心架構來看,分為三個階段:

ShuffleWriter:

Map任務使用ShuffleWriter完成資料的聚集和傳送,採用多執行緒非同步傳送;使用堆外記憶體,記憶體管理統一交由spark原生記憶體管理系統,避免額外記憶體開銷,降低OOM風險。為了提高發送資料的穩定性,我們設計了中間切換目的ShuffleWorker的共,當正在傳送的ShuffleWorker出現故障,Writer端可以立即切換目的Worker,繼續傳送資料。

ShuffleWorker:

Shuffle負責將資料彙集,同時將資料落到分散式檔案系統中。ShuffleWorker的效能和穩定性,我們做了很多設計,包括流量控制,定製的執行緒模型,訊息解析定製,checksum機制等。

ShuffleReader:

ShuffleReader直接從分散式檔案系統讀取資料,不經過ShuffleWorker。為匹配不同的儲存系統讀資料的特性,Reader端我們做了Pipeline read優化。

經過以上的多種優化,我們使用線上大作業測試,ShuffleService能夠加速30%左右。

4.2 OPPO小檔案解決方案

小檔案問題的解決,我們希望對使用者是透明的,不需要使用者介入,引擎側通過修改配置即可解決。在瞭解了Spark寫入檔案的機制後,我們自研了透明的解決小檔案方案。

Spark任務在最後寫入資料的過程,目前有三種 Commit 方式:

(V1,V2,S3 commit), 我們以V1版本的Commit方式介紹一下我們的小檔案解決方案。

圖8:Spark Commit V1 示意圖

Spark的V1版本Commit,分為兩個階段,Task側的commit和Driver側的commit。Task側的commit,負責將該Task本身產生的檔案挪到Task級的臨時目錄;Driver側的commit將整所有的Task commit的臨時目錄挪到最終的目錄,最後建立_SUCCESS檔案,標誌作業執行成功。

我們實現了自己的CommitProtocol,在Driver commit階段的前段加入合併小檔案的操作,掃描:

${output.dir.root}_temporary/${appAttempt}/ 目錄下面的小檔案,然後生成對應的合併小檔案作業。合併完小檔案,再呼叫原來的commit,將合併後的檔案挪到${output.dir.root}/ 目錄下。

圖9:Spark Commit 階段合併小檔案示意圖

這種方式巧妙的避免顯性的提交額外的作業對結果資料合併,同時,在Driver commit挪動結果檔案的時候挪動的檔案數成數量級的降低,減少檔案挪動的時間消耗。目前,我們已經在國內和海外環境全部上線小檔案合併。

4.3 OPPO Yarn Router-多叢集資源協調

前面我們提到多叢集的主要的缺點是導致資源孤島,叢集的負載不均衡,整體資源利用率低。下面我們抽象出簡單的示意圖:

圖10:多叢集資源使用不均衡示意圖

從示意圖上看,左邊代表pending作業,右邊代表叢集資源情況;長度代表資源量多少,顏色代表資源負載,越深代表負載越高。很明顯可以看出來,目前的各個叢集資源負載不均衡,同時pending作業情況也跟叢集的資源使用比成比例,比如Y1叢集的資源負載很高,但是pending作業也很高,Y3叢集資源很空閒,但是這個叢集沒有作業pending。

這種問題,我們如何解決?

我們引入了社群的Yarn Router功能,使用者提交的任務到router,router再分配到各個yarn叢集,實現聯邦排程。

社群版本的Router策略比較單一,只能通過簡單的比例分配路由到不同的叢集。這種方式只能簡單實現路由作業的功能,對叢集的資源使用和作業執行情況沒有感知,所以,做出來的決策依然會導致叢集負載不均勻,例如:

圖11: 叢集1 資源負載情況

圖12: 叢集2 資源負載情況

為了徹底解決負載均衡的問題,我們自研了智慧路由策略。

ResourceManager實時向router上報自身叢集的資源和作業執行情況,給出資源釋放量的預測,router根據各個叢集上報的資訊,產生全域性的檢視。根據全域性檢視,router做出更合理的路由決策。

圖13:OPPO Yarn Router

總體上看,有了一個全域性視野的Router角色,多叢集場景下,充分發揮多叢集的優勢,同時避免多叢集的不足。未來,我們計劃賦予Router更多的能力,不僅用來解決作業pending,提升資源利用率。還將從作業執行效率方面做更多的工作,讓作業和計算、儲存資源做更好的匹配,讓計算更有價值。

4.4 元資料擴充套件利器——Waggle Dance

Waggle Dance為Hive MetaStore提供路由代理,是Apache 開源專案。Waggle Dance完全相容HiveMetaStore原生介面,無縫接入現有系統,實現對使用者透明升級,這也是我們選擇該技術方案的主要原因。

Waggle Dance的工作原理是將現有的Hive資料庫按照庫名分別路由到不同組的Metastore,每一組Metastore對應獨立的MySQL DB 例項,實現從物理上隔離元資料。

圖14:Waggle-Dance元資料切分示意圖

上面的示意圖,左邊是原始的 HiveMetastore架構,從架構圖本身來看,整體架構存在明顯的單點問題,同時資料交換流程不夠優美。使用Waggle Dance升級後,整體架構更加清晰,更加優美。Waggle Dance作為元資料交換的“匯流排”,將上層計算引擎的請求按照庫名路由到對應的Metastore。

我們在做線上切分元資料實際操作過程中,總體Metastore停機時間在10分鐘以內。我們對Waggle Dance做了定製優化,加了資料快取層,提升路由效率;同時,將Waggle Dance與我們的內部管理系統整合,提供介面話的元資料管理服務。

4.5  計算統一入口——Olivia

為了解決Spark任務提交入口的問題,我們還是將目光投向了開源社群,發現Livy可以很好的解決SparkSQL的任務提交。

Livy是一個提交Spark任務的REST服務,可以通過多種途徑向Livy提交作業,比如我們常用的是beeline提交sql任務,還有其他的比如網路介面提交;

任務提交到Livy後,Livy向Yarn叢集提交任務,Livy client生成Spark Context,拉起Driver。Livy可以同時管理多個Spark Context,支援batch和interactive兩種提交模式,功能基本類似HiveServer。

圖15:Livy架構示意圖(引自官網)

Livy能滿足我們的需求嗎?我們先看Livy本身有哪些問題。

我們總結的Livy主要有三個缺陷:

缺乏高可用:Livy Server程序重啟或者服務掉線,上面管理的Spark Context session將會失控,導致任務失敗。

缺乏負載均衡:Livy Server的任務分配是一個隨機過程,隨機選取zk名稱空間的一個Livy Server,這種隨機過程會導致一組Livy Server負載不均衡。

對spark submit作業支援不足:對於spark submit提交的jar包任務,目前支援的不完善。

圖16:Olivia 架構示意圖

針對上面的幾個問題,我們基於Livy自研了Olivia,是一種高可用、負載均衡、同時支援spark submit jar包任務以及python指令碼的計算統一入口。

Olivia使用域名提交作業,使用者不用感知具體是哪臺Server支援作業提交和管理。後臺使用一致性Hash實現負載均衡,如果有Server上下線,也會自動完成負載均衡。對於故障轉移,我們使用zk儲存spark session資訊,某個server出現問題,對應管理的session會自動轉移到其他的server管理。對於Spark submit任務的支援,我們新增一個Olivia client角色,該client會自動將jar包以及python指令碼上傳到叢集,方便Olivia Server提交作業。

4.6 總攬

前面介紹了我們對五種問題的解決方案,串聯起來就是我們今天的主題:大資料離線計算平臺的演進。

在這一章的最後,我們從整理看一下目前的離線計算架構檢視。

圖17:OPPO 大資料平臺架構示意圖

由上到下,我們可以抽象出六層,分別是:

Job Submit:這層主要是我們的離線作業排程Oflow,完成任務的定時排程,dag 管理,作業執行管理;核心功能就是實現了任務的提交。

Job Control:這層主要有HiveServer、Livy、Olivia這些任務控制組件,負責任務向叢集提交和管控。

Compute Engine:引擎層主要使用Spark和MR。

Shuffle Service:這層是為Spark引擎提供shuffle 服務,後續Shuffle Service也將承接Flink引擎的 shuffle 資料。

MetaData Control:Waggle Dance和MetaStore以及底層的MySQL形成我們的元資料控制層,使用了Waggle Dance是我們的元資料管理更靈活。

Resource Control:資源控制層,就是我們的計算資源,主要由Yarn Router來控制各個叢集的作業路由,各個Yarn叢集完成資源的管理和作業執行。我們不僅在Router上有自研的策略,我們在RM資源排程上也探索了更多的排程模式,比如:動態標籤、資源限售、更智慧的搶佔排程。

OPPO離線計算平臺發展展望

技術的發展演進一直在進行,OPPO的離線計算未來是什麼樣子,這也是我們一直在思索的命題。我們考慮從縱向和橫向兩個方向都要兼顧。

5.1 橫向思索

橫向上,考慮與其他資源和計算模式打通融合。

我們正在與彈性計算團隊合作,將大資料與雲上資源打通,利用線上服務和大資料計算兩種模式的錯峰特性,充分利用公司現有資源,實現在離線混合排程。

同時,我們跟實時計算團隊合作,探索更適合實時計算的排程模式。

5.2 縱向思索

縱向上,我們思考如何將現有架構做的更深入,更精細化。

大HBO概念:我們在探索一種大HBO概念的架構升級,從Oflow 到 yarn排程,再到spark引擎以及OLAP引擎的HBO優化。核心是提供更快、更自動、成本更低的計算。

Shuffle的繼續演進,思考後續Shuffle的演進,與引擎作業排程更加融合,提供spark 批計算的Pipeline計算形式。同時,考慮在 Shuffle Service加入Shuffle Sorter角色,將sort過程挪到Shuffle Service層,將spark sort運算元並行化,加速sort操作。

最後,感謝大家的關注,歡迎大家多多交流大資料計算的技術思考。

作者簡介

David OPPO高階資料平臺工程師

主要負責OPPO大資料離線計算方向架構設計開發,曾在國內一線大廠參與自研大資料計算引擎開發。對大資料平臺建設有比較豐富的經驗。

推薦閱讀

| 剖析Spark資料分割槽之Spark streaming&TiSpark

| Spark SQL小檔案問題在OPPO的解決方案

| YARN的介紹及實踐探索

本文版權歸OPPO公司所有,如需轉載請在後臺留言聯絡。