B站基於Flink的海量使用者行為實時ETL實踐
1、背景
在數倉分層架構體系中,從 ODS層到 DWD層資料轉換需要進行資料清洗、脫敏、列式壓縮等步驟。在B站使用者行為埋點資料 ODS到 DWD層轉換過程中,為了解決日增千億條、20+TB/天增量規模下資料重複攝取帶來的資源嚴重消耗的問題,引入了北極星(B站使用者埋點行為分析鏈路)分流,按照部門進行分表。在埋點設計中使用spmid模型,將事件型別拆分為瀏覽 pv、曝光 show、點選 click等多個事件型別,並以這些事件型別作為除天、小時分割槽以外的第三級分割槽,再以事件型別產品來源作為四級分割槽。透過基於部門業務區分按照埋點事件型別+產品來源以多表多分割槽控制的形式,最大程度降低下游任務檔案資料攝取數量以減少資源消耗。
如圖所示,使用者埋點由邊緣上報 bfe-agent到閘道器 gateway,經過kafka資料緩衝後透過 lancer collector資料分發至 ods hive,再透過北極星分流完成 ODS到 DWD層資料轉換。DWD層資料服務於搜尋推薦、推薦、廣告、AI等應用場景。在原有 ODS到 DWD資料轉換中使用Spark離線分流方案。
2、Spark離線分流方案
Spark小時任務定期調起 ETL任務完成 DWD分流、資料同步,由於在讀 ods時由於源表資料量過大造成 Spark快取 miss,繼續分流需要重新讀全表資料存在讀放大問題造成檔案重複攝取。
離線分流讀放大問題
隨著各部門中心業務的擴充套件,分流表日益增加,而在使用離線Spark sql分流過程中由於多表寫入會重複讀取源表資料,而源表的資料規模過大造成快取失效,從而重複攝取源表資料的讀放大問題日漸顯現。
分流任務資源消耗高
ODS-DWD同步資源消耗因重複攝取 ODS源表檔案跟隨分流表擴充套件持續增加,部分資源使用不合理。
DWD同步時效性低
在分割槽通知排程模式下,DWD層資料只會在ODS表分割槽通知才會進行同步,為了保證 DWD表的及時產出需大量資源滿足同步需要。在高峰期資源使用出現堆積時 ods-dwd同步容易超過1h+。
為了解決這些問題,我們引入新的解決方案--基於Flink的實時增量計算。
3、Flink實時增量計算
如下圖所示,實時北極星增量計算方案由 Flink HDFS File Source透過掃描 Lancer任務每次 checkpoint產出的可見檔案進行增量消費計算,與維表資料join之後打寬,分發至 Flink Multi Hive Sink,在這裡完成多表多分割槽分流,sink內部整合 Archer(B站大資料任務排程系統)排程下游搜尋、推薦、廣告等資料分析業務。由於 Main表檔案數量在實時分割槽寫入場景下檔案數依然過高,因此在sink表之後對Main表單獨新增基於Spark的小檔案合併。
增量計算方案預期收益主要包含:
讀放大問題解決
Flink DAG支援 Source資料下發之後可自定義分割槽輸出無需重複攝取,用以解決讀放大問題。
分流資源降低
在解決讀放大問題後,源表資料攝取只會執行一次,降低資源消耗。另外在 ODS產生一批可見檔案即進行計算,最大程度降低分流任務同步資源消耗。
時效性提升
時效性由小時級最高可提高至分鐘級,增量計算即在 ODS產生一批檔案之後就會對檔案進行消費,理論最高可在 ODS分割槽歸檔之後的一次 Checkpoint間隔即可完成 DWD表資料完全同步。
4、多級分割槽小檔案解決方案
實時分流在解決以上幾個問題同時,在灰度上線過程中發現檔案數量相比離線分流方案增長超100倍,下游Spark分析任務在讀取實時分流表載入檔案時由於檔案讀放大問題導致記憶體不足執行失敗。於是解決小檔案問題將成為該方案最終落地是否成功的關鍵。由於實時分流在每5min一次 Checkpoint執行檔案斬斷會產生大量小檔案,導致ns讀寫壓力變大,下游Spark在讀取目錄過程中也增加資源消耗導致任務執行超時。在分析了落地檔案後發現很多小檔案是由於四級分割槽併發度分配不合理導致 bucket的數量增加從而產生大量的小檔案。因此透過在保證計算能力下盡力減少 bucket數量則可以降低開啟的檔案數量。
4.1 基於 Flink Partitioner Shuffle最佳化
在270+四級分割槽下,按照全併發分配模式,每天將產生約1億4千萬檔案數。透過使用 Flink Partitioner,對於 Reader下發的資料按照所屬四級分割槽進行加簽(tag),根據每個 tag對應歷史分割槽落地資料大小比例配比計算subtask分配區間,在分配區間內隨機分發至某個 subtask,檔案數量由原來一億四千萬/天降為150w/天。檔案數縮減100+倍。
最佳化前
270 (四級分割槽) * 1800 (併發度) * 12 (每小時檔案斬斷次數) * 24 (每天小時數) = 139968000 (約14000w)。
最佳化後
5000 (Shuffle數量) * 12(每小時檔案斬斷次數) * 24 (每天小時數) = 1440000(150w) 。
如上圖所示,可能存在大量 partition僅需一個 bucket分桶即可完成檔案落地,不需要所有Bucket處理。因此按照 partition所需 bucket數量進行合理分配是解決問題的關鍵。
但是這裡有個弊端,在出現流量激增場景下,該方案可能會導致部分subtask熱點從而導致任務出現嚴重堆積(如佩洛西事件,導致部分subtask流量超過平時12+倍),需要手動調整 shuffle方案以消除熱點。這樣導致運維成本較高,並且使用者在使用該方案時門檻較高,需要長時間的壓測除錯才能將多分割槽之間的比例調整均勻。如果能夠將實時作業處理能力與檔案數量之間根據流量自動平衡,這樣運維成本可以降低另外使用者在使用時無門檻,只需配置開關即可。因此提出 Auto Shuffle推測執行以解決小檔案合併問題。
4.2 Auto Shuffle推測執行小檔案解決方案
1、支援自定義分桶 Tag規則
根據 row的欄位來確認分桶的規則,支援根據udf自定義。
2、計算 row的大小
直接按照 row位元組數大小計算,即為row的壓縮前大小。
3、滾動視窗+類揹包演算法+統一字典排序
滾動視窗
以環形陣列的形式記錄配額,配額在分配後,各個 subtask對桶內的更新相互間未知的,很容易造成單桶超過8g,現在想到的解決辦法是透過8G/一個小時內滾動時間視窗的次數/併發度來調整。
統一字典排序
主要目標是為了合併揹包演算法結果,儘可能將不同 subtask相同tag分發到相同的桶裡(由於tag分發排序不穩定)。上線選擇使用 tag hashcode排序,減少計算量。
加簽揹包演算法
類似Flink1.12小檔案合併採用的BinPack策略,在此基礎上新增Tag識別,每個分桶歸屬於單個Tag。注意在使用以上基於weight加簽揹包的計算結果 shuffle時,容易受到作業反壓的影響從而導致上圖 shuffle operator接收到的資料變少,由於JM無法區分流量降低和反壓影響,因此會根據 weight主動降低 subtask配額,這樣會導致shuffle運算元後續運算元處理能力下降,繼而增加反壓陷入惡性迴圈,在測試過程中效果表現不佳。後續在參考根據各四級分割槽落地檔案大小預設比例的思想,取消主動降低 subtask配額的操作,按照上游分發的大小按比例分配subtask,效果表現良好,但檔案數量會略高於預設比例(比例調整會導致檔案數量增加)。
4、維護比例模型狀態
在堆積恢復時按照重啟前最後一次生成的比例模型來計算 subtask分發,減少因啟動造成檔案數膨脹問題(486000單次checkpoint增量)。
5、冷啟動問題解決
由於冷啟動時,沒有流量參考,為了降低檔案數只能透過計算tag佔用方式分發subtask,這樣的累加操作為O(n),在初始化時cpu壓力較大,吞吐不達預期。因此支援UDF預設定tag規則以及比例,按照該比例進行預分發,在第一次視窗計算前按照預設比例進行O(1)分發。
5、Flink增量計算方案落地
在落地過程中,我們面臨很多問題和挑戰,尤其是在降本增效的大背景下,對於新方案落地提出了高要求。首先面臨的是在資源緊缺情況下如何適應相對物理機叢集而言環境較為惡劣的混部叢集。在混部環境下需要實時任務做到以下幾點:
(事前)分流任務穩定性提升
(事中)分流任務需快速恢復,即 Fast-FailOver
(事後)分流任務頻繁重啟下不影響資料質量
基於這樣的要求,在實時分流任務中在 Flink Runtime\SQL\Connector以及實時平臺層應用很多功能最佳化以滿足要求。
5.1 分流任務穩定性提升
首先影響任務穩定的主要有以下幾點:
JobManager穩定性問題
Subtask間負載均衡
Subtask熱點傾斜
解決方案:
5.1.1 JobManager穩定性問題解決
Metrics Disabled
我們在查詢 JobManager掛的RC過程中,發現經常由於 JobManager OOM導致任務重啟,尤其在開啟原生監控時經常出現。在 Dump記憶體進行分析後發現,Jobmanager記憶體80%以上儲存的是各個 TM上報的 Metrics,由於開啟原生監控會主動 pull額外的Metrics從而加重記憶體壓力導致 OOM。因此實現 Metrics Disabled關閉部分Metrics對JM上報,問題解決。
JobManager HA
在混部環境下 JobManger常會因所在 Container被驅逐而導致Jobmanager掛掉。因此透過開啟JM HA在JobManger掛掉的過程中,保持TM執行狀態,並重連JobMaster,取消社群JM心跳超時就Cancel Task的行為以保證任務持續穩定執行。
5.1.2 Subtask間負載均衡
基於backlog負載均衡
非hash shuffle場景下,Flink預設提供了rebalance或rescale partitioner用於在下游運算元的不同並行度間均勻地分發資料(round-robin方式)。在環境問題(例如機器異構等)導致下游運算元的不同並行度之間處理能力不均衡時,會導致部分subtask資料堆積,造成反壓。為此,我們引入了下游subtask之間的負載均衡機制,並預設提供了基於backlog進行負載均衡的實現。透過運用該負載均衡機制,可以使得資料根據下游subtask的處理能力進行分發,減少環境問題導致的反壓等問題。
5.1.3 Subtask傾斜問題解決
Reader File Split負載均衡
File Split在 Round Robin分發時,由於split大小不同以及機器異構等原因,造成部分subtask處理split速度變慢導致熱點堆積。透過JobManager維護Reader運算元執行狀態,在Monitor非同步執行緒分發時根據各reader運算元是否空閒來分配split,以類似生產者-消費者模式實現Reader運算元對於File split處理負載均衡。
5.2 分流任務快速恢復
由於實時分流任務以較小資源流式增量消費,在北極星較大流量場景下任務在重啟的幾分鐘內會造成嚴重堆積,另外在重啟過程中可能出現資源搶佔造成實時任務無法及時恢復,因此需要實時分流任務具備快速恢復的能力。主要從以下幾點出發,增加恢復速度
Checkpoint快速恢復
維表Join支援FailOver
Yarn排程資源搶佔解決
5.2.1 Checkpoint快速恢復
Regional Checkpoint
北極星分流場景下Flink作業的並行度非常大,非常容易因為環境波動等原因導致部分subtask的checkpoint失敗。預設配置下,這會導致作業的checkpoint失敗,從而導致在作業恢復時需要重放大量的資料,造成不必要的資源浪費。透過引入regional checkpoint,可以做到在部分subtask的checkpoint失敗時,作業的checkpoint仍然可以成功。配合Flink社群提供的region failover的功能,可以極大地提高作業在部分subtask失敗時從checkpoint恢復的速度。
配置引數:execution.checkpointing.regional.enabled=true,execution.checkpointing.regional.max-tolerable-consecutive-failures-or-expiratinotallow=3,execution.checkpointing.regional.max-tolerable-failure-or-expiration-ratio=1,execution.checkpointing.tolerable-failed-checkpoints=3
5.2.2 維表Join支援FailOver
ShutDown Hook Failover
在北極星分流場景下,使用 HDFS維表 Left Join。HDFS維表載入過程是定期將 HDFS檔案反序列化並以 KV形式放入記憶體和 RocksDB中,快取級別為 TM級。一旦出現 slot通訊失敗將 shutdown整個 TM,快取需重新載入。透過 JDK1.0提供的 ShutDown Hook在 slot失敗時單獨清理 Slot物件,保留 TM級別快取,支援 Region FailOver在 slot單獨恢復時提高恢復速度。
5.2.3 Yarn排程資源搶佔
Session提交
在叢集資源緊張的情況下,任務重啟時會發生由於資源被Pending任務搶佔而無法啟動的問題。這會導致高優任務的資源需求無法滿足,時常需要人工介入處理。透過Session提交方式,在任務漂移時保留佔用的資源不釋放,保證任務 FailOver成功。
5.3 分流任務資料質量保證
在任務頻繁重啟過程中,容易觸發各功能點的Corner Case導致資料質量異常。在考慮功能的健壯性基礎上,結合Flink兩階段提交能力保證資料處理Exactly Once。ODS資料在分流任務處理過程中主要經過Flink File Source以及Multi Hive Sink,在Flink connectors實現過程中結合Checkpoint實現資料處理 Exactly Once。另外在維表Join處理上,也可能發生維表Join異常導致DQC異常。
5.3.1 File Source兩階段提交
檔案處理Exactly Once
透過掃描ODS表目錄並根據目錄下索引檔案得到可見檔案,基於分割槽寫入檔案修改時間單調遞增的特性,Checkpoint記錄已轉換Splits的檔案最大Modify Time。任務重啟後掃描的檔案過濾出小於記錄的modify time即可保證檔案處理精確一次。
Split分發Exactly Once
檔案在轉換Split之後,將會由Monitor統一下發至Reader運算元,在分發過程中,Monitor負責記錄未傳送的split,Reader運算元記錄已接收的split,保證split分發不丟不重。
Split轉換RowData Exactly Once
Split在轉換為RowData過程中,原生的 HiveTableFileInput不支援Checkpoint,沒有記錄split,任務在重啟時會導致split重複讀取導致資料重複。透過改造在checkpoint時記錄當前每個Split處理的SplitNumber,在重啟恢復Reopen Split時從上次記錄的Split Number處開始消費,保證Split轉換RowData時精確一次。
5.3.2 維表載入資料準確性
維表載入降級
由於維表載入需要訪問外部系統,容易產生異常導致維表載入失敗。由於業務存在根據維表載入的資料進行where過濾,一旦維表資料異常則會發生資料丟失。因此在維表載入資料異常時主動降級至上一個分割槽,雖然可能會導致部分新的資料join miss,但在最大程度上降低資料丟失風險。
檔案鎖保證原子性
內部在使用維表join時,選擇了直接透過載入hdfs目錄的方式載入資料。在沒有使用分割槽通知機制的情況下,載入是否完成只能透過Spark是否寫完作為最終標誌,由於是天級別目錄小時級更新場景,因此對於檢查SUCCESS檔案的方法並不具備原子性。透過加檔案鎖的方式,即判斷載入資料前後的檔案時間是否發生變更保證HDFS維表載入原子性。
5.3.3 Multi Hive Sink資料質量保證
檔案兩階段處理
這裡使用社群版本,即在寫出檔案時為隱藏檔案,執行 Checkpoint時Close檔案,在下一次checkpoint成功之後notify執行rename操作保證資料一致性。
多表多級分割槽提前排程問題
在內部分流場景下,為了減小下游資料攝取數量,由二級分割槽分流成為四級分割槽,四級分割槽在社群版本分割槽提交過程中,由於排程是小時級別,則需要判斷該分割槽下所有四級分割槽全部ready之後才能通知下游排程,僅透過watermark無法滿足該要求。我們透過在狀態中記錄Flink Bucket的Open和Close狀態,來判斷當前小時分割槽下所有的四級分割槽是否完全結束。
整合archer新增Archer commit policy
傳統實時排程離線的方法透過打時間差方式進行,需要平臺側透過定時排程拉起下游,為了保證不被提前調起,還要加分割槽是否建立兜底保障,排程任務拉起與上游分割槽通知存在gap。透過archer commit主動通知方式可以解決這一gap帶來的排程不準確的問題,因此透過整合archer在hive commit運算元內增加archer commit policy,對分流表下游排程基於主動通知的模式拉起,保障資料質量和排程準確性。
6、實時增量計算落地效果
實時增量計算在北極星分流場景落地後,相比原有離線分流方案在各方面有顯著提升。
資源使用降低
在資源使用上整體資消耗降低約20%,峰值資源消耗降低約46%。
資料時效性提升
小時級分割槽歸檔時間平均提升20%,在 ODS-DWD ETL平均2TB每小時資料場景下,小時級同步99線保持30min內,50線在17min內。
分割槽可擴充套件性增強
支援在同步資源不變條件下繼續拆分多表多級分割槽。
7、未來展望
在實時數倉流批一體的大背景下,實踐透過 Flink+Hudi方式打造北極星分流流批一體,整合實時離線鏈路降低資源開銷,並且透過 Hudi clustering能力進一步降低讀取資料量,達到查詢加速的效果。
來自 “ 嗶哩嗶哩技術 ”, 原文作者:朱正軍;原文連結:http://server.it168.com/a2023/0406/6797/000006797632.shtml,如有侵權,請聯絡管理員刪除。
相關文章
- B站基於ClickHouse的海量使用者行為分析應用實踐
- 基於 Flink 的實時數倉生產實踐
- 錢大媽基於 Flink 的實時風控實踐
- Flink基礎:實時處理管道與ETL
- 快手基於 Apache Flink 的實時數倉建設實踐Apache
- 基於flink的電商使用者行為資料分析【3】| 實時流量統計
- 網易雲音樂基於Flink實時數倉實踐
- 基於Flink流處理的動態實時超大規模使用者行為分析
- 美團點評基於 Flink 的實時數倉建設實踐
- Flink 在 B 站的多元化探索與實踐
- 基於flink的電商使用者行為資料分析【2】| 實時熱門商品統計
- B站基於Iceberg的湖倉一體架構實踐架構
- 快手基於 Flink 構建實時數倉場景化實踐
- 基於 Flink 的小米資料整合實踐
- Flink-電商使用者行為分析(實時對賬)
- B 站構建實時資料湖的探索和實踐
- 【Flink】基於 Flink 的流式資料實時去重
- 基於 Flink CDC 的實時同步系統
- 基於網站的使用者行為分析網站
- Apache Hudi 在 B 站構建實時資料湖的實踐Apache
- 基於Kafka和Elasticsearch構建實時站內搜尋功能的實踐KafkaElasticsearch
- Flink 實踐教程-入門(8): 簡單 ETL 作業
- B站基於K8S的雲原生混部技術實踐K8S
- 幸福裡基於 Flink & Paimon 的流式數倉實踐AI
- 基於 Flink CDC 的現代資料棧實踐
- HDFS EC在B站的實踐
- Flink 在有贊實時計算的實踐
- 攜程基於Flink的實時特徵平臺特徵
- Flink CDC + Hudi 海量資料入湖在順豐的實踐
- 基於Flink的超大規模線上實時反欺詐系統的建設與實踐
- Oceanus:基於Apache Flink的一站式實時計算平臺Apache
- 基於flink和drools的實時日誌處理
- GaussDB(DWS)基於Flink的實時數倉構建
- DWDM技術在B站基礎工程的落地實踐之路
- Doris和Flink在實時數倉實踐
- 基於Redis、Storm的實時資料查詢實踐RedisORM
- Airwallex 基於 Flink 打造實時風控系統AI
- 基於Apache Hudi + Flink的億級資料入湖實踐Apache