數據治理實踐 | 網易某業務線的計算資源治理

本文從計算資源治理實踐出發,帶大家清楚認識計算資源治理到底該如何進行,並如何應用到其他項目中。

01前言

由於數據治理層面可以分多個層面且內容繁多(包括模型合規、數據質量、數據安全、計算/存儲資源、數據價值等治理內容),因此需要單獨拆分爲6個模塊單獨去闡述其中內容。

筆者作爲數倉開發經常會收到大量集羣資源滿載、任務產出延時等消息/郵件,甚至下游數分及其他同學也會詢問任務運行慢的情況,在這裏很多數倉同學遇到這類問題第一想到的都是加資源解決,但事實真不一定是缺少資源,而是需要優化當前問題任務。所以本期從團隊做計算資源治理視角出發,帶大家清楚認識計算資源治理到底該如何進行。

02問題出現

在做計算治理之前(2022.12)我們團隊盤點了下當前計算資源存在的幾個問題:

(1)30+高消耗任務:由於數倉前中期業務擴張,要覆蓋大量場景應用,存在大量問題代碼運行時數據傾斜,在消耗大量集羣計算資源下,產出時間也久;

(2)200w+的小文件:當前任務存在未合併小文件、任務Reduce數量過多、上游數據源接入(尤其是API數據接入)會造成過多小文件出現,小文件過多會開啓更多數據讀取,執行會浪費大量的資源,嚴重影響性能;

(3)任務調度安排不合理:多數任務集中在凌晨2-5點執行且該區間CPU滿載,導致該時間段資源消耗成了重災區,所有核心/非核心任務都在爭搶資源,部分核心任務不能按時產出一直在等待階段;

(4)線上無效DQC(數據質量監控)&監控配置資源過小:存在部分歷史任務沒下線表及DQC場景,每日都在空跑無意義DQC浪費資源,同時DQC資源過少導致DQC需要運行過長時間;

(5)重複開發任務/無用任務:早期協助下游做了較多煙囪數據模型,因爲種種原因,部分任務不再被使用,煙囪模型分散加工導致資源複用率降低;

(6)任務缺少調優參數&部分任務仍然使用MapReduce/Spark2計算引擎:任務缺少調優參數導致資源不能適配及動態調整,甚至線上仍有早期配置MapReduce/Spark2計算引擎導致運行效率較低。

03思考與行動

3.1 治理前的思考:

在治理之前我想到一個問題,切入點該從哪裏開始最合適?

經過與團隊多次腦暴對當前治理優先級/改動成本大小/難度做了一個排序,我們先選擇從簡單的參數調優&任務引擎切換開始->小文件治理->DQC治理->高消耗任務治理->調度安排->下線無用模型及沉澱指標到其他數據資產,同時在初期我們完成各類元數據接入搭建治理看板以及團隊治理產出統計數據模型,並通過網易數帆提供的數據治理平臺解決具體細節問題。


數據治理平臺截圖

3.2 治理行動:

(1)大部分任務切換至Spark3計算引擎&補充任務調優參數

補充Spark調優參數(參數內容詳見文末),任務統一使用Spark3引擎加速,並充分利用Spark3的AQE特性及Z-Order排序算法特性。

AQE解釋:Spark 社區在 DAG Scheduler 中,新增了一個 API 在支持提交單個 Map 階段,以及在運行時修改 shuffle 分區數等等,而這些就是 AQE,在 Spark 運行時,每當一個 Shuffle、Map 階段進行完畢,AQE 就會統計這個階段的信息,並且基於規則進行動態調整並修正還未執行的任務邏輯計算與物理計劃(在條件運行的情況下),使得 Spark 程序在接下來的運行過程中得到優化。

Z-Order解釋:Z-Order 是一種可以將多維數據壓縮到一維的技術,在時空索引以及圖像方面使用較廣,比如我們常用order by a,b,c 會面臨索引覆蓋的問題,Z-Order by a,b,c 效果對每個字段是對等的

(2)小文件治理

在這裏我們使用內部數據治理平臺-數據治理360對存在小文件較多表提供內容展示(本質採集HDFS對應路徑下文件數的日誌去顯示)

當前小文件處理:

對於分區較多使用Spark3進行動態分區刷新,(Spark3具備小文件自動合併功能,如未使用Spark3可配置Spark3/Hive小文件合併參數刷新,參數詳見文末),代碼如下:

1 set hive.exec.dynamic.partition.mode=nonstrict;
2 insert overwrite table xxx.xxx partition (ds)
3 select column
4 ,ds
5 from xxx.xxx

對於分區較少或未分區的表採用重建表,補數據方法回刷。

小文件預防:

  • 使用Spark3引擎,自動合併小文件
  • 減少Reduce的數量(可以使用參數進行控制)
  • 用Distribute By Rand控制分區中數據量
  • 添加合併小文件參數
  • 將數據源抽取後的表做一個任務(本質也是回刷分區合併小文件任務)去處理小文件保障從數據源開始小文件不向下游流去

(3)DQC治理

無效DQC下線:難點在於需要查找所有DQC對應的線上任務,查看該DQC任務是否與線上任務一一匹配,從而找到無效DQC任務下線,內容繁雜耗時較多。

DQC資源:由於之前DQC配置資源爲集羣默認參數,效率極低導致所有DQC運行時長均超過10min,從而使得整體任務鏈路運行時長過久,調整Driver內存爲2048M,Executor個數爲2,Executor內存爲4096M

(4)高消耗任務調優

這裏存在2個難點:優化效果不可控、高消耗任務調整到何種程度算合適,針對這個這個難點我們取所有核心數據資產任務均值,保障單個任務消耗小於平均消耗,同時我們針對當前高消耗任務列舉出如下可優化的方式:

  • 關聯表過多,需拆分
  • 關聯時一對多,數據膨脹
  • 資源配置過多,運行時資源嚴重浪費,需要將配置調小(包括Driver內存、Executor個數、Executor內存)
  • 代碼結尾添加Distribute By Rand(),用來控制Map輸出結果的分發
  • 查詢中列和行未裁剪、分區未限定、Where條件未限定
  • SQL中Distinct切換爲Group by(Distinct會被hive翻譯成一個全局唯一Reduce任務來做去重操作,Group by則會被hive翻譯成分組聚合運算,會有多個Reduce任務並行處理,每個Reduce對收到的一部分數據組,進行每組聚合(去重))
  • 關聯後計算切換爲子查詢計算好後再關聯
  • 使用Map Join(Map Join會把小表全部讀入內存中,在Map階段直接拿另外一個表的數據和內存中表數據做匹配,由於在Map是進行了Join操作,省去了Reduce運行的效率也會高很多)可用參數代替

(5)任務調度合理優化

對於調度優化一開始會無從下手,統計凌晨2-5點區間下大概600+任務難梳理,同時存在任務依賴,修改起來可能會對下游整體有大的影響,因此我們選擇循序漸進先梳理再改善。

  • 找到所有表的輸出輸入點即啓始ODS與末尾ADS
  • 劃分其中核心表/非核心表,及對應任務開始時間與結束時間
  • 按照梳理內容把非核心的任務穿插在當前集羣資源非高峯時期(2點前與5點後),同時把核心任務調度提前,保障CDM層任務及時產出
  • 對實踐後內容再度調優,達到資源最大利用率

(6)煙囪任務下沉&無用任務下線

煙囪表過多,需下沉指標到DWS中提升複用性,對於無用任務也需要及時下線(這裏需要拿到元數據血緣最好到報表層級的數據血緣,防止任務下線後導致可視化內容問題產生),減少開發資源消耗。

04治理效果

(1)Hive與Spark2任務升級Spark3.1,總計升級任務137個,升級任務後總體任務執行效率提升43%,cpu資源消耗降低41%,內存資源消耗降低46%

(2)治理小文件數大於10000+以上的數倉表總計30+張,小文件總數由216w下降至67w

(3)下線無效DQC任務總計50+,修改DQC配置資源降低運行時長,由原來10min優化至3min內

(4)完成線上20+個任務優化及10+個任務下線及10+表指標下沉,優化後節省任務耗時146分鐘,減少CPU損耗800w+,降低內存消耗2600w+(相當於節省了8個200+字段1億數據量任務消耗)

(5)調度重新分配後2-5點資源使用率由90+%降低至50+%,保障日用資源趨勢圖無大突刺波動

05小結

計算資源治理核心在於降本增效,用有限資源去運行更多任務,通過一系列治理操作也讓數倉同學積累技術經驗同時規範化自身開發標準,讓治理反推進組內技術進步。

計算資源治理是一件長久之事,並不能因爲資源緊張纔去治理,而要將計算治理常態化,可通過周/月資源掃描內容及時推送給每個同學,併爲之打分,讓每個任務都有源可循,有方法可優化。

參數內容

參數並不是設置越多任務性能越好,根據數據量、消耗、運行時間進行調整達到合理效果。

Hive:

(1)set hive.auto.convert.join = true; (是否自動轉化成Map Join)

(2)set hive.map.aggr=true; (用於控制負載均衡,頂層的聚合操作放在Map階段執行,從而減輕清洗階段數據傳輸和Reduce階段的執行時間,提升總體性能,該設置會消耗更多的內存)

(3)set hive.groupby.skewindata=true; (用於控制負載均衡,當數據出現傾斜時,如果該變量設置爲true,那麼Hive會自動進行負載均衡)

(4)set hive.merge.mapfiles=true; (用於hive引擎合併小文件使用)

(5)set mapreduce.map.memory.mb=4096; (設置Map內存大小,解決Memory佔用過大/小)

(6)set mapreduce.reduce.memory.mb=4096;(設置Reduce內存大小,解決Memory佔用過大/小)

(7)set hive.exec.dynamic.partition.mode=nonstrict;(動態分區開啓)

Spark:

(1)set spark.sql.legacy.parquet.datetimeRebaseModeInRead=LEGACY;(用於spark3中字段類型不匹配(例如datetime無法轉換成date),消除sql中時間歧義,將Spark .sql. LEGACY . timeparserpolicy設置爲LEGACY來恢復Spark 3.0之前的狀態來轉化)

(2)set spark.sql.adaptive.enabled=true;(是否開啓調整Partition功能,如果開啓,spark.sql.shuffle.partitions設置的Partition可能會被合併到一個Reducer裏運行。平臺默認開啓,同時強烈建議開啓。理由:更好利用單個Executor的性能,還能緩解小文件問題)

(3)set spark.sql.hive.convertInsertingPartitionedTable=false;(解決數據無法同步Impala問題,使用Spark3引擎必填)

(4)set spark.sql.finalStage.adaptive.advisoryPartitionSizeInBytes=2048M;(Spark小文件合併)

作者簡介: 語興,網易數據開發工程師。

限時開放,免費試用網易數據治理產品

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章