本文以我們在實時數倉選型的經驗為切入點,進一步著重分享使用Doris過程中遇到的問題以及我們針對這些問題所做出的調整和優化。
1 背景
1.1 業務場景
根據業務需求,目前有道精品課的數據層架構上可分為離線和實時兩部分。 離線系統主要處理埋點相關數據,採用批處理的方式定時計算。
而實時流數據主要來源於各個業務系統實時產生的數據流以及資料庫的變更日誌,需要考慮數據的準確性、實時性和時序特徵,處理過程非常複雜。
有道精品課數據中臺團隊依託於其實時計算能力在整個數據架構中主要承擔了實時數據處理的角色,同時為下游離線數倉提供實時數據同步服務。
數據中臺主要服務的用戶角色和對應的數據需求如下:
運營/策略/負責人主要查看學生的整體情況,查詢數據中臺的一些課程維度實時聚合數據輔導/銷售主要關注所服務學生的各種實時明細數據品控主要查看課程/老師/輔導各維度整體數據,通過T+1的離線報表進行查看數據分析師對數據中臺T+1同步到離線數倉的數據進行交互式分析1.2 數據中臺前期系統架構及業務痛點
如上圖所示,在數據中臺1.0架構中我們的實時數據存儲主要依託於Elasticsearch,遇到了以下幾個問題:
聚合查詢效率不高數據壓縮空間低不支持多索引的join,在業務設計上我們只能設置很多大寬表來解決問題不支持標準SQL,查詢成本較高2 實時數倉選型
基於上面的業務痛點,我們開始對實時數倉進行調研。當時調研了Doris, ClickHouse, TiDB+TiFlash, Druid, Kylin。
由於起初我們數據中臺只有兩名開發,而且存儲相關的東西需要自行運維,所以我們對運維的成本是比較敏感的,在這一方面我們首先淘汰了Kylin和ClickHouse。
在查詢方面,我們的場景大多為明細+聚合多維度的分析,所以Druid也被排除。
最後我們對聚合分析的效率方面進行對比,由於Doris支持Bitmap和RollUp,而TiDB+TiFlash不支持,所以我們最終選擇了Doris來作為我們數據中臺的主存儲。
3 基於Apache Doris的數據中臺2.0
3.1 架構升級
在完成了實時數倉的選型後,我們針對Doris做了一些架構上的改變以發揮它最大的作用,主要分為以下幾個方面:
Flink雙寫
將所有FlinkJob改寫,在寫入Elasticsearch的時候旁路輸出一份數據到Kafka,並對複雜嵌套數據創建下遊任務進行轉化發送到Kafka,Doris使用RoutineLoad導入數據。
Doris on ES
由於之前我們的實時數倉只有ES,所以在使用Doris的初期,我們選擇了通過Doris創建ES外表的方式來完善我們的Doris數倉底表。同時也降低了查詢成本,業務方可以無感知地使用數倉底表。
具體查詢Demo如下所示,我們通過學生的基礎信息Join各種練習信息,對學生數據進行補齊。
數據同步
原來我們使用ES的時候,由於很多表沒有數據寫入時間,數據分析師需要每天掃全表導出全量數據到Hive,這對我們的集群有很大壓力,並且也會導致數據延遲上升,我們在引入了Doris後,對所有數倉表都添加 eventStamp, updateStamp, deleted這三個欄位。
eventStamp:事件發生時間updateStamp:Doris數據更新時間,在Routine Load中生成deleted:數據是否刪除,由於我們很多實時數倉需要定時同步到離線數倉,所以數據需要採取軟刪除的模式數據對下遊同步時可以靈活的選擇eventStamp或者updateStamp進行增量同步。
數據同步我們採用了多種方式,通過Hive表名後綴來決定不同同步場景:
_f:每天/每小時全量同步,基於Doris Export全量導出_i:每天/每小時增量同步,基於Doris Export按分區導出/網易易數掃表導出_d:每天鏡像同步,基於Doris Export全量導出
指標域劃分/數據分層
將Elasticsearch中的數據進行整理並結合後續的業務場景,我們劃分出了如下四個指標域:
根據上面的指標域,我們基於星型模型開始構建實時數倉,在Doris中構建了20餘張數倉底表以及10餘張維表,通過網易易數構建了完整的指標系統。
微批生成DWS/ADS層
由於我們多數場景都是明細+聚合數據的分析,所以我們基於Doris insert into select的導入方式,實現了一套定時根據DWD層數據生成DWS/ADS層數據的邏輯,延遲最低可以支持到分鐘級,整體的多層數倉表計算流程如下圖:
對於明細數據在TiDB或者ES的,我們選擇了在Flink中進行窗口聚合寫入到下遊Doris或者ES中。而對於明細數據只在Doris單獨存在的數據,由於我們大部分使用了異步寫入的方式,所以數據無法立即可讀,我們在外圍構建了支持模版化配置的定時執行引擎,支持分鐘/小時級別的掃描明細表變更寫入下遊聚合表,具體模版配置如下圖:
需要對監聽的源表以及變更欄位進行配置,在配置的interval時間窗口內多個源表進行掃描,然後將結果進行merge後生成參數,根據配置的threshold對參數進行拆分後傳入多個insert sql中,並在每天凌晨進行T+1的全量聚合,修復微批計算的錯誤數據。
具體的計算觸發邏輯如下圖:
數據血緣
我們基於拉取Routine Load和Flink數據以及服務上報的方式實現了數據中臺完善的數據血緣,供數據開發/數據分析師進行查詢。
由於我們的Flink開發模式為提交jar的形式,為了獲取到任務的血緣,我們對每個算子的命名進行了格式化封裝,血緣服務定時的拉取/v1/jobs/overview數據進行解析,我們將不同算子的格式命名封裝為以下幾種:
Source:sourceTypeName [address] [attr]Sink:sinkTypeName [address] [attr]具體的血緣服務邏輯如下圖所示:
通過血緣服務內部的解析後,批量地將血緣數據拆分成了Node與Edge存儲到了NebulaGraph中,前臺服務進行查詢即可獲得如下圖所示的一條完整血緣:
3.2 數據中臺2.0架構
基於圍繞Doris的系統架構調整,我們完成了數據中臺2.0架構
使用網易易數數據運河替換Canal,擁有了更完善的數據訂閱監控Flink 計算層引入 Redis/Tidb 來做臨時/持久化緩存複雜業務邏輯拆分至 Grpc 服務,減輕 Flink 中的業務邏輯數據適配層新增 Restful 服務,實現一些 case by case 的複雜指標獲取需求通過網易易數離線調度跑通了實時到離線的數據同步新增了數據報表/自助分析系統兩個數據出口
4 Doris帶來的收益
1. 數據導入方式簡單,我們針對不同業務場景使用了三種導入方式
Routine Load:實時異步數據導入Broker Load:定時同步離線數倉數據,用於查詢加速Insert into:定時通過DWD層數倉表生成DWS/ADS層數倉表2. 數據佔用空間降低,由原來Es中的1T左右降低到了200G左右
3. 數倉使用成本降低
Doris支持MySQL協議,數據分析師可以直接進行自助取數,一些臨時分析需求不需要再將Elasticsearch數據同步到Hive供分析師進行查詢。一些在ES中的明細表我們通過Doris外表的方式暴露查詢,大大降低了業務方的查詢成本。同時因為Doris支持Join,原來一些需要查詢多個Index再從內存中計算的邏輯可以直接下推到Doris中,提升了查詢服務的穩定性,加快了響應時間。聚合計算速度通過物化視圖和列存優勢獲得了較大提升。5 上線表現
目前已經上線了幾十個實時數據報表,在線集群的P99穩定在1s左右。同時也上線了一些長耗時分析型查詢,離線集群的P99穩定在1min左右。
同時我們基於Doris完成了標準化數倉的構建,在數據開發上跑通了一套完整的流程,使我們數據需求的日常迭代更加迅速。
6 總結和規劃
Doris的引入推進了有道精品課數據分層的構建,加速了實時數倉的規範化進程。
數據中臺團隊在此基礎上一方面向全平臺各業務線提供統一的數據接口,並依託於Doris生產實時數據看板,另一方面定時將實時數倉數據同步至下游離線數倉供分析師進行自助分析,為實時和離線場景提供數據支撐。
對於後續工作的開展,我們做了如下規劃:
基於Doris明細表生成更多的上層聚合表,降低Doris計算壓力,提高查詢服務的整體響應時間基於Flink實現Doris Connector,實現Flink對Doris的讀寫功能開發Doris on ES支持嵌套數據的查詢最後感謝百度Palo(Doris)團隊的鼎力支持,為我們提供了很多技術上的幫助,在問題的解決上也十分迅速,為我們數據中臺的飛速發展提供了可靠的支持。
關於 Apache Doris(Incubating)
Apache Doris(Incubating)一款基於大規模並行處理技術的交互式SQL分析資料庫,由百度於2018年貢獻給 Apache 基金會,目前在 Apache 基金會孵化器中。