導讀: 福建縱騰網絡有限公司(簡稱“縱騰集團”)成立于 2009 年, 以“全球跨境電商基礎設施服務商”為企業定位,聚焦跨境倉儲與物流, 為全球跨境電商商戶、出口貿易企業、出海品牌商提供海外倉儲、商業專線物流、定制化物流等一體化物流解決方案, 旗下擁有谷倉海外倉 、云途物流 、WORLDTECH 等知名品牌 。
隨著縱騰集團業務的快速發展,各產品線提出的數據需求越發嚴格,而早期基于多套 CDH 大數據架構的技術棧和組件繁雜,開發和運維難度高、效率低,數據質量和時效難以保障,已無法滿足當下數據分析需求,嚴重影響相關工作的開展。因此,縱騰集團在 2022 年正式引入 Apache Doris,基于 Apache Doris 構建了新的流批一體數據架構,同時建立了以 Apache Doris 為核心的數據中臺。 構建過程中對讀寫時效性、服務的穩定性及高并發讀寫等多方面進行了優化,在這一過程中我們也積累了諸多實踐經驗,在此總結分享給大家。
早期架構
早期數倉架構主要分為兩套基于 CDH 的大數據集群,這兩套架構用于不同產品線的數倉需求、數據大屏和 BI 報表等應用。


這兩套架構為獨立的數據管道,具有耦合度低,集群間相互獨立等特點,便于精細化管理。但隨著業務需求的不斷變化,這樣的特點也引發出許多新的問題。
遇到的問題
- 元數據和數據質量缺乏管控,數據質量無法得到保證
- 不同業務數據獨立存儲維護導致數據孤島,不利于數據整合
- 每個集群的機房分布不一,維護成本非常高
- 集群間的技術棧和組件較多且存在差異性,對統一開發運維和數據整合都極具挑戰性
架構選型
為了解決早期架構的痛點、更好滿足日益嚴苛的數據需求,我們希望能有一款產品幫助我們快速構建流批一體的數倉架構、構建數據中臺服務。

我們對傳統數倉、 實時數倉和數據湖進行了對比。從上圖可知,傳統數倉可以支撐超 PB 級的海量數據,但是交互查詢性能相對差一些,偏離線場景,不滿足我們對數據實時性的要求;數據湖可以支撐超海量的數據,支持數據更新,查詢性能適中,但是數據湖近兩年才開始應用,成熟度較低,使用風險較大;實時數倉適用 PB 級數據存儲,支持數據更新且查詢性能非常好。結合我們的要求,實時數倉與我們的使用和需求場景都比較貼合,因此我們最終決定選擇實時數倉作為數據底座。
接著我們對市面上較為流行的三款實時數倉:ClickHouse、Apache Druid、Apache Doris 進行了選型對比,對比圖如下:

對比可知,Apache Doris 優勢明顯、性價比更高,具有獨立主從架構簡單、運維更靈活便捷、豐富的數據模型、優秀的查詢性能和周全的生態規劃等諸多優勢,對比這三個產品,Apache Doris 最符合我們的選型要求。
新數據架構

新數據架構基于 Apache Doris 簡化了數據采集、存儲和計算的流程:
- 結合 DataHub 實現自研元數據采集和周期管理
- 通過 Seatunnel 集成 Flink Doris Connector 稍加改造實現全量加增量數據的一體化采集
- 簡化存儲媒介,對 ClickHouse、Kudu、HBase 等技術棧進行收斂,由 Apache Doris 進行流批數據的統一存儲
- 以 Apache Doris 為核心數據底座,結合 Apache Kyuubi 的 JDBC 引擎直連查詢(自研)和 Spark 引擎中的 Spark Doris Connector 進行 ETL 開發(原生),統一計算引擎管理、權限管控和對外服務。
基于上述幾點進行了數據應用開發及對外提供數據服務,構建了數據中臺。
數據中臺
我們以 Apache Doris 為核心底座創建了數據平臺,核心功能包括:指標中心、元數據中心、基礎配置中心、即席分析和數據接口服務中心,其中指標中心和即席分析的數據主要來源于 Aapche Doris ,當前已上線幾百個指標。

數倉建模
我們結合 Apache Doris 的特性重新對數倉進行了建模,數倉分層與傳統數倉類似,其中 ODS 數據為存量加增量一體的導入模式,同時為防止出現[隨機查詢結果問題],ODS 層最終選用 Unique 數據模型,相比于 Aggregate 模型可以實現寫時合并(Merge-on-Write),有效提高數據實時性,且 Aggregate 模型查詢性能更接近于 Duplicate 模型,對于 ODS 層是非常好的選擇。
DIM/DED/DWS/ADS 層主要選用 Aggregate 數據模型;Aggregate 數據模型提供的四種聚合方式可以在大部分場景下達到事半功倍的效果,幫助我們快速應對不同的需求場景。
- SUM: 能夠高效實現 PV 類指標計算,但對于 UV 類的指標需要考慮預去重。
- MAX/MIN: 常用于最大最小運單時間節點類指標或包裹體積/重量最大最小值的指標計算。
- REPLACE_IF_NOT_NULL: 可以自動地過濾空值,非常便捷地實現僅記錄最后一條數據,適用于大部分 DW 場景。

數據導入
ODS 層的數據導入目前主要以 Stream Load 為主,在 HDFS 上的歷史存量數據也會通過 Broker Load 或Spark Load 導入。DW 層數據主要以 insert into 方式導入,同時為減輕 Doris 內存壓力,我們將部分 ETL 任務放到 Kyuubi On Spark 引擎上去計算,目前在 DolphinScheduler 每天平穩調度 Doris DW 任務有上萬個,其中大部分為 T+1 任務,小部分為小時級任務。

實踐經驗

對于以 Apache Doris 為核心的新數據架構,我們規劃了6個階段進行運行測試,直至可以上線運行。(重點關注壓測階段和運行階段,有一些調試優化經驗分享給大家)
1、準備階段
引入 Apache Doris 時是 2022 年 2月,因此選擇當時最新版本 Apache Doris 0.15 Release 版本進行應用,主要考慮維度如下:
- 支持事務性插入語句功能
- 支持 Unique Key 模型下的 Upsert
- 支持 SQL 阻塞 List 功能,可以通過正則、哈希值匹配等方式防止某些 SQL 的執行
- 官方不支持跨兩位版本號進行升級,而 0.15 為當時最新的 Release 版本,選用該版本利于后期版本升級
- 可通過資源標簽的方式將一個Apache Doris 集群中的 BE 節點劃分為多個資源組,實現多租戶和資源隔離
- 該版本提供了官方認可的 Flink-Doris-Connector/Spark-Doris-Connector/DataX Doriswriter 等插件,利于ETL流程建設
2、驗證階段
該階段主要是為了二次驗證官方文檔中介紹的功能是否滿足我們的實際運用場景,比如生態擴展中的 Connector、外表聯邦查詢、各種 Load 方式、多租戶隔離及物化視圖等。
3、壓測階段

壓測階段首先進行數據生成,數據集選用的是 TPC-DS 數據,接著根據 Doris 的特性對 DDL 和 SQL 等規則進行對應調整,最后通過腳本將數據導入到 Apache Doris 存儲中,再通過自動化腳本進行查詢及導入壓測,最終將壓測結果輸出到 MySQL 表中,量化為圖表進行展示。下方為本階段的基本配置及壓測過程介紹:
- 硬件環境
- 內存:256G
- CPU:96C
- 硬盤:SSD 1.92T * 8
- 軟件環境
- Apache Doris 版本:0.15-release/1.0-release(該階段進行時,1.0-release 版本剛好發布)
- Apache Doris 集群:3 FE + 9 BE
- 系統:CentOS Linux release 7.9.2009
- 數據集信息
我們生成了 1T、5T、10T 的 TPC-DS 數據集,1T 的數據集約有 30 億數據量。

查詢壓測

壓測過程中,最初使用 0.15-release 版本進行測試,正巧 1.0-release 版本發布,后決定更換為 1.0-release 版本進行后續的壓測。下圖是基于 1T 的 TPC-DS 數據在同等硬件配置環境下和某商業 MPP 數據庫的對比結果:

如圖所示,Apache Doris 的查詢壓測性能優異,有著明顯的性能優勢,作為開源產品能夠達到這樣的效果是非常優秀也是十分不易的。
導入壓測
- 導入方式:通過 DataX Doriswriter 以 StreamLoad 方式進行寫入壓測
- 數據來源:為避免因 Source 端原因影響寫入時效,選擇 100 張相同大表,即 100 個并發從內網 Hive 中導入(例如 tpcds-ds 的 store_sales_1t 表)
- 數據模型:選用 Unique 模型(模擬ODS層),同時為充分考慮 Compaction 性能及小文件場景,每張表設置 70 個 Tablet
經調整優化后,最大寫入時效為 269 MB/S&680K ops/s,平均寫入時效 70 MB/S&180K ops/s,寫入時效大幅提升。

4、上線階段
該階段主要是確認 Apache Doris 上線需要的檢查清單、預調參數、BE 資源組規劃及用戶權限的劃分。
- 檢查清單:包括但不限于 FE & BE 端口、網絡檢查及 Apache Doris 的一些功能性驗證,例如讀寫是否正常等。
- 預調參數:確認優化后的 FE&BE 參數是否配置,是否開啟
global enable_profile、動態分區以及數據盤保存位置是否有誤等。 - BE 資源組:由于我們需要通過 Apache Doris 的多租戶特性對不同的用戶進行資源隔離,所以需要提前規劃好每個 BE 節點對應的資源組。
- 用戶權限:對于不同的用戶群體提前規劃好權限范圍,比如分析師開發只需要
SELECT_PRIV權限,而 ETL 工程師需要SELECT_PRIV、LOAD_PRIV和CREATE_PRIV權限。
5、宣導階段
該階段主要是輸出前面各階段的 TimeLine、總結以及上線后使用 Apache Doris 的注意事項說明,比如我們用到多租戶隔離,那么 DDL 建表時則需要在 Properties 中顯示指定各副本對應的資源組:
create table zt_table
......
properties(
? "replication_allocation"="tag.location.group_a:1, tag.location.group_b:1, tag.location.group_c:1"
)
6、運行階段
Tablet 規范問題
問題描述: 上線運行一段時間后,隨著越來越多的數據增長,集群每次重啟后一周左右,讀寫就會開始變得越來越慢,直到無法正常進行讀寫。
問題處理:
- 經過對生產和 UAT 環境的對比測試以及對數倉表的 Schema 的分析,我們發現有些表數據并不大,但是 Bucket 卻設置的非常大。

- 結合
show data from database命令,我們將整個集群所有表的 Bucket 信息羅列出來,明確了大部分表的 Bucket 設置的不合理;而當前集群共 20T 左右數據,平均 1T 數據近 10W 個 Tablet,這就會導致小文件過多,造成 FE 元數據負載過高,從而影響導入和查詢性能。 - 定位原因后與社區小伙伴二次確認,并根據官方建議將 Bucket 設置不合理的表全部調整,調整后集群逐步恢復讀寫正常。(即將發布的 Apache Dorie 1.2.2 版本將推出 Auto Bucket 動態分桶推算功能,可以根據歷史數據和機器數目自動推算新建 Partition 的分桶個數,保證分桶數始終保持在合理范圍內,可有效解決上述問題)
問題小結:
- Tablet數 = 分區數 * 桶數 * 副本數
- 1TB 數據的 Tablet 數量控制在 8000 個左右(三副本控制到 2.4W 左右)
- 建議大表的單個 Tablet 存儲數據大小在 1G-10G 區間,可防止過多的小文件產生
- 建議百兆左右的維表 Tablet 數量控制在 3-5 個,保證一定的并發數也不會產生過多的小文件
集群讀寫優化
問題描述: 1.1.3 release 版本中,高并發的同時進行 Stream Load、Broker Load、insert into 和查詢時,讀寫會變得非常慢,如下圖 11/01 19:00 并發上來后的 Txn Load 所示:

問題處理:
\1. 我們進行了十幾輪對比測驗,結論如下:
-
- 寫入速度與并發的增長成反比(但不會驟變,而是緩慢變化)
- 單表 Bucket(Tablet)設置過大會導致集群寫入速度驟減;例如 A 庫的 TA 表,設置 80 個 Bucket 時,啟動相關 Flink Sink Job 就會導致集群整體寫入速度迅速變慢,降低 Bucket(9~10個)時寫入恢復正常。
insert into select的 ETL 任務與 Stream Load 寫入任務會進行資源搶占,同時并發運行會使整個集群讀寫變慢。

\2. 通過be.INFO發現,80 個 Bucket 表寫入某個 Tablet 的memsize/rows/flushsize/duration數值比 10 個 Bucket 寫入時的數值呈數倍之差,即 80 個 Bucket 表的數據寫入時效無論 Memsize 還是 Flushsize 都非常小、但花費時間卻很長。

\3. 同時收集 Pstack 日志,經過分析可以確定,Tcmalloc 在頻繁地尋找 pageheap_lock,導致高頻競爭鎖從而降低了讀寫性能。

\4. 于是,進行如下參數調整:
減少doris_be進程內存返回給linux系統的頻率,從而減少tcmalloc頻繁競爭鎖的情況
tc_use_memory_min = 207374182400
tc_enable_aggressive_memory_decommit = false
tc_max_total_thread_cache_bytes=20737418240
\5. 調參并滾動重啟 BE 后,集群狀況如下圖所示:
18:50 前將 Broker Load、insert into 和查詢任務同時開啟,18:50 后將 Stream Load 任務也開啟(包括 80 bucket的表),集群整體的讀寫性能不僅沒有下降,反而 Stream Load 時效突破了壓測階段的最大值 269 MB/S&680K /ops/s,并且持續穩定。

問題小結:
使用 Apache 1.1.3 及以上版本,非常推薦調整 Tcmalloc 相關參數,減少doris_be進程與系統之間的內存申請回收過程,可明顯減少鎖競爭的現象,大大提升讀寫性能和集群穩定性。(從 Apache Doris 1.1.5 版本開始,增加了Tcmalloc 簡化配置,可將眾多 Tcmalloc 參數歸約到參數memory_mode中,compact 為節約內存模式,performance 為性能模式,用戶可根據實際需求進行調整)
總結收益
當前 Apache Doris 的生產集群為 3 FE + 9 BE 組合, 已導入集團存量和增量數據的 60%以及部分 DW 數據生成,3 副本共占 44.4TB 的存儲。

依賴 Apache Doris 自身優異特性及其生態圈幫助我們快速構建了一套新的流批一體數據架構,平均每天實時入庫的數據量達到上億規模,同時支持上萬個調度任務平穩運行,相比早期架構單表**查詢效率提升近 5 倍 **,數據導入效率提升近 2 倍,內存資源使用率顯著減少。除此之外,Apache Doris 以下優勢也是我們快速構建數據架構的重要推動力:
- 擴展表:聯邦查詢的設計,便于集成其它存儲
- 數據表設計:豐富的數據模型,可快速應對不同的數據需求。
- 數據查詢:不同的 Join 算子結合自身完善的優化器,讓查詢快而穩。
- 架構設計:架構清晰明了且運維簡單,大大地降低了我們的運維成本。
- 數據導入:各種 Load 方式及 Connector 的擴展,基本涵蓋大部分的數據同步場景應用。
- 活躍度:社區高度活躍,SelectDB 為 Apache Doris 社區組建了一支專職技術支持團隊,疑難雜癥基本能在 12H 內快速響應并有社區小伙伴跟進和協助解決。
未來規劃
結合當下業務場景的考慮,未來我們將引入數據湖進行非結構化和結構化數據一體存儲,進一步完善流批一體架構。同時也會將 Apache Doris 回歸它最本質的定位,專注于 OLAP 分析場景,并通過 Apache Doris 統一湖倉查詢引擎層,發揮其最大的功效。

最后,非常感謝 Apache Doris 社區和 SelectDB 團隊的張家鋒、曲率和楊勇強等小伙伴對我們無私的技術支持,未來我們也將持續參與 Apache Doris 社區建設中,貢獻綿薄之力。祝 Apache Doris 社區和 SelectDB 越來越好,日臻完善!
