導讀: 隨著天眼查近年來對產品的持續(xù)深耕和迭代,用戶數(shù)量也在不斷攀升,業(yè)務的突破更加依賴于數(shù)據(jù)賦能,精細化的用戶/客戶運營也成為提升體驗、促進消費的重要動力。在這樣的背景下正式引入 Apache Doris 對數(shù)倉架構進行升級改造,實現(xiàn)了數(shù)據(jù)門戶的統(tǒng)一,大大縮短了數(shù)據(jù)處理鏈路,數(shù)據(jù)導入速率提升 75 %,500 萬及以下人群圈選可以實現(xiàn)毫秒級響應,收獲了公司內部數(shù)據(jù)部門、業(yè)務方的一致好評。
業(yè)務需求
天眼查的數(shù)據(jù)倉庫主要服務于三個業(yè)務場景,每個場景都有其特點和需求,具體如下:
- 億級用戶人群圈選: 人群圈選場景中目前有 100+ 人群包,我們需要根據(jù) SQL 條件圈選人群包,來支持人群包的交并差、人群包實時圈選和人群包更新通知下游等需求。例如:圈選出下單未支付超過 5 分鐘的用戶,我們通過用戶標簽可以直觀掌握用戶支付狀態(tài),為運營 & 營銷團隊提供更精細化的人群管理服務,從而提高轉化率。
- 多元活動支撐的精準營銷: 該場景目前支持了 1000 多個指標,可支持即席查詢,根據(jù)活動效果及時調整運營策略。例如在“開工季”活動中,需要為數(shù)據(jù)分析 & 運營團隊提供數(shù)據(jù)支持,從而生成可視化的活動駕駛艙。
- 高并發(fā)的 C 端分析數(shù)據(jù): 該場景承載了 3 億+實體(多種維度)的數(shù)據(jù)體量,同時要求實時更新,以供用戶進行數(shù)據(jù)分析。
原有架構及痛點
為滿足各業(yè)務場景提出的需求,我們開始搭建第一代數(shù)據(jù)倉庫,即原有數(shù)倉:
在原有數(shù)倉架構中, Hive 作為數(shù)據(jù)計算層,MySQL、ES、PG 作為數(shù)據(jù)存儲層,我們簡單介紹一下架構的運行原理:
- 數(shù)據(jù)源層和數(shù)據(jù)接入層: MySQL 通過 Canal 將 BinLog 接入 Kafka、埋點日志通過 Flume 接入 Kafka,最后由 DataX 把 Kafka 中的數(shù)據(jù)接入數(shù)據(jù)計算層 Hive 中;
- 數(shù)據(jù)計算層: 該層使用 Hive 中的傳統(tǒng)的數(shù)倉模型,并利用海豚調度使數(shù)據(jù)通過 ODS -> DWD -> DWS 分層,最后通過 DataX 將 T+1 把數(shù)據(jù)導入到數(shù)據(jù)存儲層的 MySQL 和 ES 中。
- 數(shù)據(jù)存儲層: MySQL 主要為 DataBank、Tableau、C 端提供分析數(shù)據(jù),ES 用于存儲用戶畫像數(shù)據(jù),PG 用于人群包的存儲(PG 安裝的插件具有 Bitmap 交并差功能),ES、PG 兩者均服務于 DMP人群圈選系統(tǒng)。
問題與挑戰(zhàn):
依托于原有架構的投入使用,初步解決了業(yè)務方的需求,但隨著天眼查近年來對產品的持續(xù)深耕和迭代,用戶數(shù)量也在不斷攀升,業(yè)務的突破更加依賴于數(shù)據(jù)賦能。精細化的用戶/客戶運營也成為提升體驗、促進消費的重要動力。在這樣的背景下,原有架構的缺點逐漸暴露:
- 開發(fā)流程冗長:體現(xiàn)在數(shù)據(jù)處理鏈路上,比如當面對一個簡單的開發(fā)需求,需要先拉取數(shù)據(jù),再經過 Hive 計算,然后通過 T+1更新導入數(shù)據(jù)等,數(shù)據(jù)處理鏈路較長且復雜,非常影響開發(fā)效率。
- 不支持即席查詢:體現(xiàn)在報表服務和人群圈選場景中,所用的指標無法根據(jù)條件直接查詢,必須提前進行定義和開發(fā)。
- T+1 更新延遲高:T+1 數(shù)據(jù)時效性已經無法提供精確的線索,主要體現(xiàn)在報表和人群圈選場景上。
- 運維難度高:原有架構具有多條數(shù)據(jù)處理鏈路、多組件耦合的特點,運維和管理難度都很高。
理想架構
基于以上問題,我們決定對架構進行升級改進,在正式升級之前,我們希望未來的架構可以做到以下幾點:
- 原架構涉及 MySQL 、PG、ES 等多個組件,并為不同應用提供服務;我們希望未來的架構可以兼容 MySQL 協(xié)議,實現(xiàn)低成本替換、無縫銜接以上組件。
- 支持即席查詢且性能優(yōu)異,即席查詢能夠給業(yè)務方提供更靈活的表達方式,業(yè)務方可以從多個角度、多個維度對數(shù)據(jù)進行查詢和分析,更好地發(fā)現(xiàn)數(shù)據(jù)的規(guī)律和趨勢,幫助業(yè)務方更精準備地做出決策。
- 支持實時聚合,以減輕開發(fā)負擔并保證計算結果的準確性。
- 統(tǒng)一數(shù)據(jù)出口,原架構中數(shù)據(jù)出口不唯一,我們希望未來的架構能更統(tǒng)一數(shù)據(jù)出口,縮短鏈路維護成本,提升數(shù)據(jù)的可復用性。
- 支持高并發(fā), C 端的實時分析數(shù)據(jù)需要較高的并發(fā)能力,我們希望未來的架構可以高并發(fā)性能優(yōu)異。
技術選型
考慮到和需求的匹配度,我們重點對 OLAP 引擎進行了調研,并快速定位到 ClickHouse 和 Apache Doris 這兩款產品,在深入調研中發(fā)現(xiàn) Doris 在以下幾個方面優(yōu)勢明顯,更符合我們的訴求:
- 標準 SQL:ClickHouse 對標準 SQL 支持有限,使用中需要對多表 Join 語法進行改寫;而 Doris 兼容 MySQL 協(xié)議,支持標準 SQL ,可以直接運行,同時 Doris 的 Join 性能遠優(yōu)于 ClickHouse。
- 降本增效:Doris 部署簡單,只有 FE 和 BE 兩個組件,不依賴其他系統(tǒng);生態(tài)內導數(shù)功能較為完備,可針對數(shù)據(jù)源/數(shù)據(jù)格式選擇導入方式;還可以直接使用命令行操作彈性伸縮,無需額外投入人力;運維簡單,問題排查難度低。相比之下,ClickHouse 需要投入較多的開發(fā)人力來實現(xiàn)類似的功能,使用難度高;同時 ClickHouse 運維難度很高,需要研發(fā)一個運維系統(tǒng)來支持處理大部分的日常運維工作。
- 并發(fā)能力:ClickHouse 的并發(fā)能力較弱是一個潛在風險,而 Doris 并發(fā)能力更占優(yōu)勢,并且剛剛發(fā)布的 2.0 版本支持了更高并發(fā)的點查。
- 導入事務:ClickHouse 的數(shù)據(jù)導入沒有事務支持,無法實現(xiàn) Exactly Once 語義,如導數(shù)失敗需要刪除重導,流程比較復雜;而 Doris 導入數(shù)據(jù)支持事務,可以保證一批次內的數(shù)據(jù)原子生效,不會出現(xiàn)部分數(shù)據(jù)寫入的情況,降低了判斷的成本。
- 豐富的使用場景:ClickHouse 支持場景單一,Doris 支持場景更加豐富,用戶基于 Doris 可以構建用戶行為分析、AB 實驗平臺、日志檢索分析、用戶畫像分析、訂單分析等應用。
- 豐富的數(shù)據(jù)模型:Doris 提供了Unique、Duplicate、Aggregate 三種數(shù)據(jù)模型,可以針對不同場景靈活應用不同的數(shù)據(jù)模型。
- 社區(qū)響應速度快:Doris 社區(qū)的響應速度是其獨有特色,SelectDB 為社區(qū)組建了一直完備的社區(qū)支持團隊,社區(qū)的快速響應讓我們少走了很多歪路,幫助我們解決了許多問題。
新數(shù)倉架構
經過對 Doris 進行綜合評估,我們最終決定采用 Doris 對原有架構進行升級優(yōu)化,并在架構層級進行了壓縮。新的架構圖如下所示:

在新架構中,數(shù)據(jù)源層和數(shù)據(jù)接入層與原有架構保持一致,主要變化是將 Doris 作為新架構的數(shù)據(jù)服務層,統(tǒng)一了原有架構中的數(shù)據(jù)計算層和存儲層,這樣實現(xiàn)了數(shù)據(jù)門戶的統(tǒng)一,大大縮短了數(shù)據(jù)處理鏈路,解決了開發(fā)流程冗長的問題。 同時,基于 Doris 的高性能,實現(xiàn)了即席查詢能力,提高了數(shù)據(jù)查詢效率。另外,F(xiàn)link 與 Doris 的結合實現(xiàn)了實時數(shù)據(jù)快速寫入,解決了 T+1 數(shù)據(jù)更新延遲較高的問題。除此之外,借助于 Doris 精簡的架構,大幅降低了架構維護的難度。
數(shù)據(jù)流圖
縮短數(shù)據(jù)處理鏈路直接或間接地帶來了許多收益。接下來,我們將具體介紹引入 Doris 后的數(shù)據(jù)流圖。

總體而言,數(shù)據(jù)源由 MySQL 和日志文件組成,數(shù)據(jù)在 Kafka 中進行分層操作(ODS、DWD、DWS),Apache Doris 作為數(shù)據(jù)終點統(tǒng)一進行存儲和計算。應用層包含 C 端、Tableau 和 DMP 系統(tǒng),通過網關服務從 Doris 中獲取相應的數(shù)據(jù)。
具體來看,MySQL 通過 Canal 把 Binlog 接入 Kafka,日志文件通過 Flume 接入 Kafka 作為 ODS 層。然后經過 Flink SQL 進行清洗、關聯(lián)維表,形成 DWD 層的寬表,并生成聚合表。為了節(jié)省空間,我們將 ODS 層存儲在 Kafka 中,DWD 層和 DWS 層主要與 Doris 進行交互。DWD 層的數(shù)據(jù)一般通過 Flink SQL 寫入 Doris。針對不同的場景,我們應用了不同的數(shù)據(jù)模型進行數(shù)據(jù)導入。MySQL 數(shù)據(jù)使用 Unique 模型,日志數(shù)據(jù)使用 Duplicate 模型,DWS 層采用 Aggregate 模型,可進行實時聚合,從而減少開發(fā)成本。
應用場景優(yōu)化
在應用新的架構之后,我們必須對業(yè)務場景的數(shù)據(jù)處理流程進行優(yōu)化以匹配新架構,從而達到最佳應用效果。接下來我們以人群圈選、C端分析數(shù)據(jù)及精準營銷線索為主要場景,分享相關場景流程優(yōu)化的實踐與經驗。
01 人群圈選

原流程(左)中,業(yè)務人員在畫像平臺頁面上利用表的元數(shù)據(jù)創(chuàng)建人群圈選任務,任務創(chuàng)建后進行人群 ID 分配,寫入到 PG 畫像表和 MySQL 任務表中。接著根據(jù)任務條件定時在 ES 中查詢結果,獲取結果后更新任務表的狀態(tài),并把 Bitmap 人群包寫入 PG。利用 PG 插件提供的 Bitmap 交并差能力操作人群包,最后下游運營介質從 PG 取相應人群包。
然而,該流程處理方式非常復雜,ES 和 PG 中的表無法復用,造成成本高、效益低。同時,原流程中的數(shù)據(jù)為 T+1 更新,標簽必須提前進行定義及計算,這非常影響查詢效率。
現(xiàn)流程(右)中,業(yè)務人員在畫像平臺創(chuàng)建人群圈選任務,后臺分配人群 ID,并將其寫入 MySQL 任務表中。首次圈選時,根據(jù)任務條件在 Doris 中進行即席查詢,獲取結果后對任務表狀態(tài)進行更新,并將人群包寫入 Doris。后續(xù)根據(jù)時間進行微批輪詢,利用 Doris Bitmap 函數(shù)提供的交并差功能與上一次的人群包做差集,如果有人群包更新會主動通知下游。
引入 Doris 后,原有流程的問題得到了解決,新流程以 Doris 為核心構建了人群圈選服務,支持人群包實時更新,新標簽無需提前定義,可通過條件配置自助生成,減少了開發(fā)時間。新流程表達方式更加靈活,為人群包 AB 實驗提供了便捷的條件。流程中采用 Doris 統(tǒng)一了明細數(shù)據(jù)和人群包的存儲介質,實現(xiàn)業(yè)務聚焦,無需處理多組件數(shù)據(jù)之間的讀寫問題,達到了降本增效的終極目標。
02 C端分析數(shù)據(jù)及精準營銷線索場景

原流程: 在原流程中,如果業(yè)務提出新需求,需要先發(fā)起需求變更,再經過評審、排期開發(fā),然后開始對 Hive 中的數(shù)據(jù)模型進行開發(fā)并進行測試,測試完成后進行數(shù)倉上線,配置 T+1 調度任務寫入 MySQL,最后 C端和精準營銷系統(tǒng)對 MySQL 數(shù)據(jù)進行讀取。原流程鏈路復雜,主要體現(xiàn)在流程長、成本高、上線周期長。
現(xiàn)流程: 當前明細數(shù)據(jù)已經在 Doris 上線,當業(yè)務方發(fā)起需求變更時,只需要拉取元數(shù)據(jù)管理平臺元數(shù)據(jù)信息,配置查詢條件,審批完成后即可上線,上線 SQL 可直接在 Doris 中進行即席查詢。相比原流程,現(xiàn)在的流程大幅縮短了需求變更流程,只需進行低代碼配置,成功降低了開發(fā)成本,縮短了上線周期。
優(yōu)化經驗
為了規(guī)避風險,許多公司的人群包user_id是隨機生成的,這些user_id相差很大且是非連續(xù)的。然而,使用非連續(xù)的user_id進行人群圈選時,會導致 Bitmap 生成速度較慢。因此,我們生成了映射表,并生成了連續(xù)稠密的user_id。當使用連續(xù) user_id 圈選人群時,速度較之前提升了 70% 。

用戶 ID 映射表樣例數(shù)據(jù):從圖可知原始用戶 ID 由多位數(shù)字組合,并且 ID 很稀疏(用戶 ID 間相差很大),而連續(xù)用戶 ID 則 從1開始,且 ID 很稠密。

案例展示:
- 用戶 ID 映射表:
用戶 ID 映射表將用戶 ID 作為唯一鍵模型,而連續(xù)用戶 ID 則通過用戶 ID 來生成,一般從 1 開始,嚴格保持單調遞增。需要注意的是,因為該表使用頻繁,因此將 in_memory 設置為true,直接將其緩存在內存中:

- 人群包表
人群包表是以用戶標簽作聚合鍵的模型,假設以 user_id 大于 0、小于 2000000 作為圈選條件,使用原始 user_id 進行圈選耗費的時間遠遠遠大于連續(xù)稠密 user_id 圈選所耗

如下圖所示,左側使用 tyc_user_id圈選生成人群包響應時間:1843ms,右側使用使tyc_user_id_continuous圈選生成人群包響應時間:543ms。消耗時間大幅縮短

規(guī)模與收益
引入 Doris 后,我們已經搭建了 2 個集群,承載的數(shù)據(jù)規(guī)模正隨著遷移的推進而持續(xù)增大。目前,我們已經處理的數(shù)據(jù)總量已經達到了數(shù)十TB,單日新增數(shù)據(jù)量已經達到了 數(shù)億條,而數(shù)據(jù)體量還在持續(xù)增長中。此外,我們在 Doris 上運行的指標和人群包數(shù)量已經超過了 500,分別涵蓋了商查、搜索、運營、用戶和營收五大類指標。
Doris 的引入滿足了業(yè)務上的新需求,解決了原有架構的痛點問題,具體表現(xiàn)為以下幾點:
- 降本增效: Doris 統(tǒng)一了數(shù)據(jù)的門戶,實現(xiàn)了存儲和計算的統(tǒng)一,提高了數(shù)據(jù)/表的復用率,降低了資源消耗。同時,新架構優(yōu)化了數(shù)據(jù)到 MySQL、ES 的流程,開發(fā)效率得到有效提升。
- 導入速率提升: 原有數(shù)據(jù)流程中,數(shù)據(jù)處理流程過長,數(shù)據(jù)的導入速度隨著業(yè)務體量的增長和數(shù)據(jù)量的不斷上升而急劇下降。引入 Doris 后,我們依賴 Broker Load 優(yōu)秀的寫入能力,使得導入速率提升了 75%以上。
- 響應速度:Doris 的使用提高了各業(yè)務場景中的查詢響應速度。例如,在人群圈選場景中,對于 500 萬及以下的人群包進行圈選時,能夠做到毫秒級響應。

未來規(guī)劃
正如前文所講,Apache Doris 的引入解決了許多架構及業(yè)務上的難題,初見成效,同時也收獲了公司內部數(shù)據(jù)部門、業(yè)務方的一致好評,未來我們將繼續(xù)探索,基于 Doris 展開更深度的應用,不久的將來,我們將重點推進以下幾個方面工作:
- 離線指標實時化:將更多的指標從離線轉為實時,提供更及時的數(shù)據(jù)服務。
- 搭建數(shù)據(jù)血緣系統(tǒng):將代碼中的血緣關系重新定義為可視,全面構建數(shù)據(jù)血緣關系,為問題排查、鏈路報警等提供有效支持。
- 探索批流一體路線:從使用者的角度思考設計,實現(xiàn)語義開發(fā)層的統(tǒng)一,使數(shù)據(jù)開發(fā)更便捷、更低門檻、更高效率。
在此特別感謝 SelectDB 團隊,作為基于 Apache Doris 的商業(yè)化公司,為社區(qū)投入了大量的研發(fā)和用戶支持力量,在使用過程中遇到任何問題都能及時響應,為我們降低了許多試錯成本。未來,我們也會更積極參與社區(qū)貢獻及活動中來,與社區(qū)共同進步和成長,歡迎大家選擇和使用 Doris,相信 Doris 一定不會讓你失望。
