Apache Doris 在思必馳的應用優化實踐:海量語音通話資料下,實時、離線一體的數倉架構設計實踐

語言: CN / TW / HK

業務背景

思必馳是一家對話式人工智慧平臺公司,擁有全鏈路的智慧語音語言技術,致力於成為全鏈路智慧語音及語言互動的平臺型企業,自主研發了新一代人機互動平臺 DUI 和人工智慧晶片TH1520,為車聯網、IoT 及政務、金融等眾多行業場景合作伙伴提供自然語言互動解決方案。

思必馳於 2019 年首次引入Apache Doris ,基於 Apache Doris 構建了實時與離線一體的數倉架構。相對於過去架構,Apache Doris 憑藉其靈活的查詢模型、極低的運維成本、短平快的開發鏈路以及優秀的查詢效能等諸多方面優勢,如今已經在實時業務運營、自助/對話式分析等多個業務場景得到運用,滿足了裝置畫像/使用者標籤、業務場景實時運營、資料分析看板、自助 BI、財務對賬等多種資料分析需求。在這一過程中我們也積累了諸多使用上的經驗,在此分享給大家。

架構演進

早期業務中,離線資料分析是我們的主要需求,近幾年,隨著業務的不斷髮展,業務場景對實時資料分析的要求也越來越高,早期數倉架構逐漸力不從心,暴露出很多問題。為了滿足業務場景對查詢效能、響應時間及併發能力更高的要求,2019 年正式引入 Apache Doris 構建實時離線一體的數倉架構。

以下將為大家介紹思必馳數倉架構的演進之路,早期數倉存在的優缺點,同時分享我們選擇 Apache Doris 構建新架構的原因以及面臨的新問題與挑戰。

早期數倉架構及痛點

如上圖所示,早期架構基於 Hive +Kylin 來構建離線數倉,實時數倉架基於 Spark+MySQL 來構建實時分析數倉。

我們業務場景的資料來源主要分為三類,業務資料庫如 MySQL,應用系統如 K8s 容器服務日誌,還有車機裝置終端的日誌。資料來源通過 MQTT/HTTP 協議、業務資料庫 Binlog 、Filebeat 日誌採集等多種方式先寫入 Kafka。

在早期架構中,資料經 Kafka 後將分為實時和離線兩條鏈路,首先是實時部分,實時部分鏈路較短,經過 Kafka 緩衝完的資料通過 Spark 計算後放入 MySQL 中進行分析,對於早期的實時分析需求,MySQL 基本可以滿足分析需求。而離線部分則由 Spark 進行資料清洗及計算後在 Hive 中構建離線數倉,並使用 Apache Kylin 構建 Cube,在構建 Cube 之前需要提前做好資料模型的的設計,包括關聯表、維度表、指標欄位、指標需要的聚合函式等,通過排程系統進行定時觸發構建,最終使用 HBase 儲存構建好的 Cube。

早期架構的優勢:

  1. 早期架構與 Hive 結合較好,無縫對接 Hadoop 技術體系。

  2. 離線數倉中基於 Kylin 的預計算、表關聯、聚合計算、精確去重等場景,查詢效能較高,在併發場景下查詢穩定性也較高。

早期架構解決了當時業務中較為緊迫的查詢效能問題,但隨著業務的發展,對資料分析要求不斷升高,早期架構缺點也開始逐漸凸顯出來。

早期架構的痛點:

  1. 依賴元件多。Kylin 在 2.x、3.x 版本中強依賴 Hadoop 和 HBase ,應用元件較多導致開發鏈路較長,架構穩定性隱患多,維護成本比很高。

  2. Kylin 的構建過程複雜,構建任務容易失敗。Kylin 構建需要進行打寬表、去重列、生成字典,構建 Cube 等如果每天有 1000-2000 個甚至更多的任務,其中至少會有 10 個甚至更多工構建失敗,導致需要大量時間去寫自動運維指令碼。

  3. 維度/字典膨脹嚴重。維度膨脹指的是在某些業務場景中需要多個分析條件和欄位,如果在資料分析模型中選擇了很多欄位而沒有進行剪枝,則會導致 Cube 維度膨脹嚴重,構建時間變長。而字典膨脹指的是在某些場景中需要長時間做全域性精確去重,會使得字典構建越來越大,構建時間也會越來越長,從而導致資料分析效能持續下降。

  4. 資料分析模型固定,靈活性較低。在實際應用過程中,如果對計算欄位或者業務場景進行變更,則要回溯部分甚至全部資料。

  5. 不支援資料明細查詢。早期數倉架構是無法提供明細資料查詢的,Kylin 官方給的解決方法是下推給 Presto 做明細查詢,這又引入了新的架構,增加了開發和運維成本。

架構選型

為解決以上問題,我們開始探索新的數倉架構優化方案,先後對市面上應用最為廣泛的 Apache Doris、Clickhouse 等 OLAP 引擎進行選型調研。相較於 ClickHouse 的繁重運維、各種各樣的表型別、不支援關聯查詢等,結合我們的 OLAP 分析場景中的需求,綜合考慮,Apache Doris 表現較為優秀,最終決定引入 Apache Doris 。

新數倉架構

如上圖所示,我們基於 Apache Doris 構建了實時+離線一體的新數倉架構,與早期架構不同的是,實時和離線的資料分別進行處理後均寫入 Apache Doris 中進行分析。

因歷史原因資料遷移難度較大,離線部分基本和早期數倉架構保持一致,在 Hive 上構建離線數倉,當然完全可以在 Apache Doris 上直接構建離線數倉。

相對早期架構不同的是,離線資料通過 Spark 進行清洗計算後在 Hive 中構建數倉,然後通過 Broker Load 將儲存在 Hive 中的資料寫入到 Apache Doris 中。這裡要說明的, Broker Load 資料匯入速度很快,天級別 100-200G 資料匯入到 Apache Doris 中僅需要 10-20 分鐘。

實時資料流部分,新架構使用了 Doris-Spark-Connector 來消費 Kafka 中的資料並經過簡單計算後寫入 Apache Doris 。從架構圖所示,實時和離線資料統一在 Apache Doris 進行分析處理,滿足了資料應用的業務需求,實現了實時+離線一體的數倉架構。

新架構的收益

  1. 極簡運維,維護成本低,不依賴 Hadoop 生態元件。Apache Doris 的部署簡單,只有 FE 和 BE 兩個程序, FE 和 BE 程序都是可以橫向擴充套件的,單叢集支援到數百臺機器,數十 PB 的儲存容量,並且這兩類程序通過一致性協議來保證服務的高可用和資料的高可靠。這種高度整合的架構設計極大的降低了一款分散式系統的運維成本。在使用 Doris 三年時間中花費的運維時間非常少,相比於基於 Kylin 搭建的早期架構,新架構花費極少的時間去做運維。

  2. 鏈路短,開發排查問題難度大大降低。基於 Doris 構建實時和離線統一數倉,支援實時資料服務、互動資料分析和離線資料處理場景,這使得開發鏈路變的很短,問題排查難度大大降低。

  3. 支援 Runtime 形式的 Join 查詢。Runtime 類似 MySQL 的表關聯,這對資料分析模型頻繁變更的場景非常友好,解決了早期結構資料模型靈活性較低的問題。

  4. 同時支援 Join、聚合、明細查詢。解決了早期架構中部分場景無法查詢資料明細的問題。

  5. 支援多種加速查詢方式。支援上卷索引,物化檢視,通過上卷索引實現二級索引來加速查詢,極大的提升了查詢響應時間。

  6. 支援多種聯邦查詢方式。支援對 Hive、Iceberg、Hudi 等資料湖和 MySQL、Elasticsearch 等資料庫的聯邦查詢分析。

問題和挑戰

在建設新數倉架構過程中,我們遇到了一些問題:

  • 高併發場景對 Apache Doris 查詢效能存在一定影響。我們分別在 Doris 0.12 和 Doris 1.1 版本上進行測試,同一時間同樣的 SQL,10 併發和 50 併發進行訪問,效能差別較大。

  • 在實時寫入場景中,當實時寫入的資料量比較大時,會使得 IO 比較密集,導致查詢效能下降。

  • 大資料量下字串精確去重較慢。目前使用的是 count distinct 函式、Shuffle 和聚合運算元去重,此方式算力比較慢。當前業內常見的解決方法一般是針對去重列構建字典,基於字典構建 Bitmap 索引後使用 Bitmap 函式去重。目前 Apache Doris 只支援數字型別的 Bitmap 索引,具有一定的侷限性。

業務場景的應用

Apache Doris 在思必馳最先應用在實時運營業務場景以及自助/對話式分析場景,本章節將介紹兩個場景的需求及應用情況。

實時運營業務場景

首先是實時運營業務場景,如上圖所示,實時運營業務場景的技術架構和前文所述的新版數倉架構基本一致:

  • 資料來源:資料來源新版架構圖中一致,包括 MySQL 中的業務資料,應用系統埋點資料以及裝置和終端日誌。

  • 資料匯入:離線資料匯入使用 Broker Load,實時資料匯入使用 Doris-Spark-Connector 。

  • 資料儲存與開發:幾乎所有的實時數倉全部在 Apache Doris 構建,有一部分離線資料放在 Airflow 上執行 DAG 跑批任務。

  • 資料應用:最上層是業務側提出的業務分析需求,包括大屏展示,資料運營的實時看板、使用者畫像、BI 看板等。

在實時運營業務場景中,資料分析的需求主要有兩方面:

  • 由於實時匯入資料量比較大,因此對實時資料的查詢效率要求較高

  • 在此場景中,有 20+ 人的團隊在運營,需要同時開資料運營的看板,因此對實時寫入的效能和查詢併發會有比較高的要求。

自助/對話式分析場景

除以上之外,Apache Doris 在思必馳第二個應用是自助/對話式分析場景。

如上圖所示,在一般的 BI 場景中,使用者方比如商務、財務、銷售、運營、專案經理等會提出需求給資料分析人員,資料分析人員在 BI 平臺上做資料看板,最終把看板提供給使用者,使用者從 BI 看板上獲取所需資訊,但是有時候使用者想要檢視明細資料、定製化的看板需求,或者在某些場景需做任意維度的上卷或者下鑽的分析,一般場景下 BI 看板是不支援的的,基於以上所述使用者需求,我們打造了自助對話式 BI 場景來解決使用者定製化的需求。

與一般 BI 場景不同的是,我們將自助/對話式 BI 場景從資料分析人員方下沉到使用者方,使用者方只需要通過打字,描述資料分析的需求。基於我們公司自然語言處理的能力,自助/對話式 BI 場景會將自然語言轉換成 SQL,類似 NL2SQL 技術,需要說明的是這裡使用的是定製的自然語言解析,相對開源的 NL2SQL 命中率高、解析結果更精確。當自然語言轉換成 SQL 後,將 SQL 給到 Apache Doris 查詢得到分析結果。由此,使用者通過打字就可以隨時檢視任意場景下的明細資料,或者任意欄位的上卷、下鑽。

相比 Apache Kylin、Apache Druid 等預計算的 OLAP 引擎,Apache Doris 符合以下幾個特點:

  • 查詢靈活,模型不固定,支援自由定製場景。

  • 支援表關聯、聚合計算、明細查詢。

  • 響應時間要快速。

因此我們很順利的運用 Apache Doris 實現了自助/對話式分析場景。同時,自助/對話式分析在我們公司多個數據分析場景應用反饋非常好。

實踐經驗

基於上面的兩個場景,我們使用過程當中積累了一些經驗和心得,分享給大家。

數倉表設計

  1. 千萬級(量級供參考,跟叢集規模有關係)以下的資料表使用 Duplicate 表型別,Duplicate 表型別同時支援聚合、明細查詢,不需要額外寫明細表。

  2. 當資料量比較大時,使用 Aggregate 聚合表型別,在聚合表型別上做上卷索引,使用物化檢視優化查詢、優化聚合欄位。由於 Aggregate 表型別是預計算表,會丟失明細資料,如有明細查詢需求,需要額外寫一張明細表。

  3. 當資料量又大、關聯表又多時,可用 ETL 先寫成寬表,然後匯入到 Doris,結合 Aggregate 在聚合表型別上面做優化,也可以使用官方推薦 Doris 的 Join 優化

寫入

  1. 通過 Spark Connector 或 Flink Connector 替代 Routine Load: 最早我們使用的是 Routine Load 實時寫入 BE 節點, Routine Load 的工作原理是通過 SQL 在 FE 節點起一個類似於 Task Manager 的管理,把任務分發給 BE 節點,在 BE 節點起 Routine Load 任務。在我們實時場景併發很高的情況下,BE 節點 CPU 峰值一般會達到 70% 左右,在這個前提下,Routine Load 也跑到 BE 節點,將嚴重影響 BE 節點的查詢效能,並且查詢 CPU 也將影響 Routine Load 匯入, Routine Load 就會因為各種資源競爭死掉。面對此問題,目前解決方法是將 Routine Load 從 BE 節點拿出來放到資源排程上,用 Doris-Spark/Flink-Connector 替換 Routine Load。當時 Doris-spark-Connector 還沒有實時寫入的功能,我們根據業務需求進行了優化,並將方案貢獻給社群。

  2. 通過攢批來控制實時寫入頻率:當實時寫入頻率較高時,小檔案堆積過多、查詢 IO 升高,小檔案排序歸併的過程將導致查詢時間加長,進而出現查詢抖動的情況。當前的解決辦法是控制匯入頻次,調整 Compaction 的合併執行緒、間隔時間等引數,避免 Tablet 下小檔案的堆積。

查詢

  1. 增加 SQL 黑名單,控制異常大查詢。個別使用者在查詢時沒有加 where 條件,或者查詢時選擇的時間範圍較長,這種情況下 BE 節點的 SQL 會把磁碟的負載和 CPU 拉高,導致其他節點的 SQL 查詢變慢,甚至出現 BE 節點宕機的情況。目前的解決方案是使用 SQL 黑名單禁止全表及大量分割槽實時表的查詢。

  2. 使用 SQL Cache 和 SQL Proxy 實現高併發訪問。同時使用 SQL Cache 和 SQL Proxy 的原因在於,SQL Cache 的顆粒度到表的分割槽,如果資料發生變更, SQL Cache 將失效,因此 SQL Cache 快取適合資料更新頻次較低的場景(離線場景、歷史分割槽等)。對於資料需要持續寫到最新分割槽的場景, SQL Cache 則是不適用的。當 SQL Cache 失效時 Query 將全部發送到 Doris 造成重複的 Runtime 計算,而 SQL Proxy 可以設定一秒左右的快取,可以避免相同條件的重複計算,有效提高叢集的併發。

儲存

使用 SSD 和 HDD 做熱溫資料儲存週期的分離,近一年以內的資料存在 SSD,超過一年的資料存在 HDD。Apache Doris 支援對分割槽設定冷卻時間,但只支援建立表分割槽時設定冷卻的時間,目前的解決方案是設定自動同步邏輯,把歷史的一些資料從 SSD 遷移到 HDD,確保 1 年內的資料都放在 SSD 上。

升級

升級前一定要備份元資料,也可以使用新開叢集的方式,通過 Broker 將資料檔案備份到 S3 或 HDFS 等遠端儲存系統中,再通過備份恢復的方式將舊叢集資料匯入到新叢集中。

升級前後效能對比

思必馳最早是從 0.12 版本開始使用 Apache Doris 的,在今年我們也完成了從 0.15 版本到最新 1.1 版本的升級操作,並進行了基於真實業務場景和資料的效能測試。

從以上測試報告中可以看到,總共 13 個測試 SQL 中,前 3 個 SQL 升級前後效能差異不明顯,因為這 3 個場景主要是簡單的聚合函式,對 Apache Doris 效能要求不高,0.15 版本即可滿足需求。而在 Q4 之後的場景中 ,SQL 較為複雜,Group By 有多個欄位、多個欄位聚合函式以及複雜函式,因此升級新版本後帶來的效能提升非常明顯,平均查詢效能較 0.15 版本提升 2-3 倍。由此,非常推薦大家去升級到 Apache Doris 最新版本。

總結和收益

  1. Apache Doris 支援構建離線+實時統一數倉,一個 ETL 指令碼即可支援實時和離線數倉,大大縮短開發週期,降低儲存成本,避免了離線和實時指標不一致等問題。

  2. Apache Doris 1.1.x 版本開始全面支援向量化計算,較之前版本查詢效能提升 2-3 倍。經測試,Apache Doris 1.1.x 版本的查詢效能已接近 ClickHouse。

  3. 功能強大,不依賴其他元件。相比 Apache Kylin、Apache Druid、ClickHouse 等,Apache Doris 不需要引入第 2 個元件填補技術空檔。Apache Doris 支援聚合計算、明細查詢、關聯查詢,當前思必馳超 90% 的分析需求已移步 Apache Doris 實現。 得益於此優勢,技術人員需要運維的元件減少,極大降低運維成本。

  4. 易用性極高,支援 MySQL 協議和標準 SQL,大幅降低使用者學習成本。

未來計劃

  1. Tablet 小檔案過多的問題。Tablet 是 Apache Doris 中讀寫資料最小的邏輯單元,當 Tablet 小檔案比較多時會產生 2 個問題,一是 Tablet 小檔案增多會導致元資料記憶體壓力變大。二是對查詢效能的影響,即使是幾百兆的查詢,但在小檔案有幾十萬、上百萬的情況下,一個小小的查詢也會導致 IO 非常高。未來,我們將做一個 Tablet 檔案數量/大小比值的監控,當比值在不合理範圍內時及時進行表設計的修改,使得檔案數量和大小的比值在合理的範圍內。

  2. 支援基於 Bitmap 的字串精確去重。業務中精確去重的場景較多,特別是基於字串的 UV 場景,目前 Apache Doris 使用的是 Distinct 函式來實現的。未來我們會嘗試的在 Apache Doris 中建立字典,基於字典去構建字串的 Bitmap 索引。

  3. Doris-Spark-Connector 流式寫入支援分塊傳輸。Doris-Spark-Connector 底層是複用的 Stream Load,工作機制是攢批,容易出現兩個問題,一是攢批可能會會出現記憶體壓力導致 OOM,二是當 Doris-Spark-Connector 攢批時,Spark Checkpoint 沒有提交,但 Buffer 已滿並提交給 Doris,此時 Apacche Doris 中已經有資料,但由於沒有提交 Checkpoint,假如此時任務恰巧失敗,啟動後又會重新消費寫入一遍。未來我們將優化此問題,實現 Doris-Spark-Connector 流式寫入支援分塊傳輸。

作者介紹

趙偉,思必馳大資料高階研發,10 年大資料開發和設計經驗,負責大資料平臺基礎技術和 OLAP 分析技術開發。社群貢獻:Doris-spark-connector 的實時讀寫和優化。