動態

詳情 返回 返回

Apache Doris 數據導入原理與性能優化 | Deep Dive - 動態 詳情

概述

對於 Apache Doris 這樣的高性能分析型數據庫而言,高效、穩定的數據導入是保障實時分析能力的生命線。然而,在海量數據持續寫入的場景下,如何平衡導入延遲與吞吐、如何避免性能瓶頸,是開發者面臨的核心挑戰。Apache Doris 本文將深入剖析 Doris 數據導入的核心原理,涵蓋關鍵流程、組件、事務管理等,探討影響導入性能的因素,並提供實用的優化方法和最佳實踐,有助於用户選擇合適的導入策略,優化導入性能。

數據導入原理

導入原理概述

Doris 的數據導入原理建立在其分佈式架構之上,主要涉及前端節點(Frontend, FE)和後端節點(Backend, BE)。FE 負責元數據管理、查詢解析、任務調度和事務協調,而 BE 則處理實際的數據存儲、計算和寫入操作。Doris 的數據導入設計旨在滿足多樣化的業務需求,包括實時寫入、流式同步、批量加載和外部數據源集成。其核心理念包括:

  • 一致性與原子性:每個導入任務作為一個事務,確保數據原子寫入,避免部分寫入。通過 Label 機制保證導入數據的不丟不重。
  • 靈活性:支持多種數據源(如本地文件、HDFS、S3、Kafka 等)和格式(如 CSV、JSON、Parquet、ORC 等),能滿足不同場景。
  • 高效性:利用分佈式架構並行處理數據,多 BE 節點並行處理數據,提高吞吐量。
  • 簡易性:提供輕量級 ETL 功能,用户可在導入時直接進行數據清洗和轉換,減少外部工具依賴。
  • 靈活建模:支持明細模型(Duplicate Key)、主鍵模型(Unique Key)和聚合模型(Aggregate Key),允許在導入時進行數據聚合或去重。

導入通用流程

Doris 的數據導入遵循一個標準化的核心流程,主要包括以下幾個階段:

1、提交導入任務

  • 用户通過客户端(如 HTTP、JDBC、MySQL 客户端)提交導入請求,指定數據源(如本地文件、Kafka Topic、HDFS 文件路徑)、目標表、文件格式和導入參數(如分隔符、錯誤容忍度)。
  • 每個任務可以指定一個唯一的 Label,用於標識任務並支持冪等性(防止重複導入)。例如,用户在 Stream Load 中通過 HTTP header 指定 Label。
  • Doris 的前端節點(FE)接收請求,驗證權限、檢查目標表是否存在,並解析導入參數。

2、任務分配與協調

  • FE 分析數據分佈(基於表的分區和桶分規則),生成導入計劃,並選擇一個後端節點(BE)作為 Coordinator,負責協調整個任務。
  • 如果用户直接向 BE 提交(如 Stream Load),BE 可直接擔任 Coordinator,但仍需從 FE 獲取元數據(如表 Schema)。
  • 導入計劃會將數據分配到多個 BE 節點,確保並行處理以提高效率。

3、數據讀取與分發

  • Coordinator BE 從數據源讀取數據(例如,從 Kafka 拉取消息、從 S3 讀取文件,或直接接收 HTTP 數據流)。
  • Doris 解析數據格式(如對 CSV 分割、JSON 解析),並支持用户定義的 輕量 ETL 操作,包括:

    • 前置過濾:對原始數據進行過濾,減少處理開銷。
    • 列映射:調整數據列與目標表列的對應關係。
    • 數據轉換:通過表達式處理數據。
    • 後置過濾:對轉換後的數據進行過濾。
  • Coordinator BE 解析完數據後按分區和桶分規則分發到多個下游的 Executor BE。

4、數據寫入

  • Doris 的高吞吐寫入得益於其獨特的數據模型與 LSM Tree(Log-Structured Merge-Tree)存儲結構的結合。LSM Tree 是一種高效的磁盤寫入優化結構,通過將寫操作分為內存和磁盤兩個階段,顯著提升了寫入性能。其核心思想是將隨機寫轉換為順序寫,減少磁盤 I/O 開銷,同時通過多級合併(Compaction)維護數據的有序性和查詢效率。
  • 數據首先分發到多個 BE(Backend)節點,寫入內存表(MemTable),並按 Key 列進行排序。對於 Aggregate 或 Unique Key 數據模型,Doris 會根據 Key 執行聚合或去重操作(如 SUM、REPLACE),減少數據冗餘,提升查詢性能。
  • 當 MemTable 寫滿(默認 200MB)或任務結束時,數據會異步寫入磁盤,形成列式存儲的 Segment 文件,並組成 Rowset。LSM Tree 的內存寫入和異步刷盤機制確保了高吞吐量,同時通過後台的 Compaction 過程定期合併 Segment 文件,優化存儲結構和查詢效率。
  • 每個 BE 節點獨立處理分配的數據,寫入完成後向 Coordinator 報告狀態,確保分佈式環境下寫入操作的可靠性和一致性。

5、事務提交與發佈

  • Coordinator 向 FE 發起事務提交(Commit)。FE 確保多數副本成功寫入後,並通知 BE 發佈數據版本(Publish Version),待 BE Publish 成功後,FE 標記事務為 VISIBLE,此時數據可以查詢。
  • 如果失敗,FE 觸發回滾(Rollback),則刪除臨時數據,以確保數據一致性。

6、結果返回

  • 同步方式(如 Stream Load、Insert Into)直接返回導入結果,包含成功/失敗狀態和錯誤詳情(如 ErrorURL)。
  • 異步方式(如 Broker Load)提供任務 ID 和 Label,用户可通過 SHOW LOAD 查看進度、錯誤行數和詳細信息。
  • 操作記錄到審計日誌,支持後續追溯。

導入衝突解決

在衝突解決方面, 經典的寫寫衝突會導致寫入無法並行,從而顯著降低寫入吞吐量。Doris 提供了基於業務語義的衝突機制,可很好避免該問題(參考文檔)。而 Redshift、Snowflake、Iceberg 和 Hudi 等則採用了文件級別的衝突處理,因而不具備實時更新的能力。

MemTable 前移

MemTable 前移是 Apache Doris 2.1.0 版本引入的優化機制,針對 INSERT INTO…SELECT 導入方式顯著提升性能,官方測試顯示該優化使得單副本導入耗時縮短約 64%(為原先的 36%),三副本導入耗時縮短約 46%(為原先的 54%),傳統流程中,Sink 節點需將數據編碼為 Block 格式,通過 Ping-pong RPC 傳輸到下游節點,涉及多次編碼和解碼,增加開銷。Memtable 前移優化了這一過程:Sink 節點直接處理 MemTable,生成 Segment 數據後通過 Streaming RPC 傳輸,減少編碼解碼和傳輸等待,同時提供更準確的內存反壓。目前該功能只支持存算一體部署模式。

存算分離導入

在存算分離架構下,導入優化聚焦數據存儲和事務管理解耦:

  • 數據存儲:BE 不持久化數據,MemTable flush 後生成 Segment 文件直接上傳至共享存儲(如 S3、HDFS),利用對象存儲的高可用性和低成本支持彈性擴展。BE 本地 File Cache 異步緩存熱點數據,通過 TTL 和 Warmup 策略提升查詢命中率。元數據(如 Tablet、Rowset 元數據)由 Meta Service 存儲於 FoundationDB,而非 BE 本地 RocksDB。
  • 事務處理:事務管理從 FE 遷移至 Meta Service,消除了 FE Edit Log 寫入瓶頸。Meta Service 通過標準接口(beginTransaction、commitTransaction)管理事務,依賴 FoundationDB 的全局事務能力確保一致性。BE 協調者直接與 Meta Service 交互,記錄事務狀態,通過原子操作處理衝突和超時回收,簡化同步邏輯,提升高併發小批量導入吞吐量。

導入方式

Doris 提供多種導入方式,共享上述原理,但針對不同場景優化。用户可根據數據源和業務需求選擇:

  • Stream Load: 通過 HTTP 導入本地文件或數據流,同步返回結果,適合實時寫入(如應用程序推送數據)。
  • Broker Load: 通過 SQL 導入 HDFS、S3 等外部存儲,異步執行,適合大規模批量導入。
  • Routine Load: 從 Kafka 持續消費數據,異步流式導入,支持 Exactly-Once,適合實時同步消息隊列數據。
  • Insert Into/Select: 通過 SQL 從 Doris 表或外部源(如 Hive、MySQL、S3 TVF)導入,適合 ETL 作業、外部數據集成。
  • MySQL Load: 兼容 MySQL LOAD DATA 語法,導入本地 CSV 文件,數據經 FE 轉發為 Stream Load,適合小規模測試或 MySQL 用户遷移。

如何提升 Doris 的導入性能

Doris 的導入性能受其分佈式架構與存儲機制影響,核心涉及 FE 元數據管理、BE 並行處理、MemTable 緩存刷盤及事務管理等環節。以下從表結構設計、攢批策略、分桶配置、內存管理和併發控制等維度,結合導入原理説明優化策略及其有效性。

表結構設計優化:降低分發開銷與內存壓力

Doris 的導入流程中,數據需經 FE 解析後,按表的分區和分桶規則分發至 BE 節點的 Tablet(數據分片),並在 BE 內存中通過 MemTable 緩存、排序後刷盤生成 Segment 文件。表結構(分區、模型、索引)直接影響數據分發效率、計算負載和存儲碎片。

  • 分區設計:隔離數據範圍,減少分發與內存壓力

通過按業務查詢模式(如時間、區域)劃分分區,導入時數據僅分發至目標分區,避免處理無關分區的元數據和文件。同時寫入多個分區會導致大量 Tablet 活躍,每個 Tablet 佔用獨立的 MemTable,顯著增加 BE 內存壓力,可能觸發提前 Flush,生成大量小 Segment 文件。這不僅增加磁盤或對象存儲的 I/O 開銷,還因小文件引發頻繁 Compaction 和寫放大,降低性能。通過限制活躍分區數量(如逐天導入),可減少同時活躍的 Tablet 數,緩解內存緊張,生成更大的 Segment 文件,降低 Compaction 負擔,從而提升並行寫入效率和後續查詢性能。

  • 模型選擇:減少計算負載,加速寫入

明細模型(Duplicate Key)僅存儲原始數據,無需聚合或去重計算;而 Aggregate 模型需按 Key 列聚合,Unique Key 模型需去重,均會增加 CPU 和內存消耗。對於無需去重或聚合的場景,優先使用明細模型,可避免 BE 節點在 MemTable 階段的額外計算(如排序、去重),降低內存佔用和 CPU 壓力,進而加速數據寫入流程。

  • 索引控制:平衡查詢與寫入開銷

索引(如位圖索引、倒排索引)需在導入時同步更新,否則會增加寫入時的維護成本。僅為高頻查詢字段創建索引,避免冗餘索引,可減少 BE 寫入時的索引更新操作(如索引構建、校驗),降低 CPU 和內存佔用,來提升導入吞吐量。

攢批優化:減少事務與存儲碎片

Doris 的每個導入任務為獨立事務,涉及 FE 的 Edit Log 寫入(記錄元數據變更)和 BE 的 MemTable 刷盤(生成 Segment 文件)。高頻小批量導入(如 KB 級別)會導致 Edit Log 頻繁寫入(增加 FE 磁盤 I/O)、MemTable 頻繁刷盤(生成大量小 Segment 文件,觸發 Compaction 寫放大),顯著降低性能。

  • 客户端攢批:減少事務次數,降低元數據開銷

客户端將數據攢至數百 MB 到數 GB 後一次性導入,減少事務次數。單次大事務替代多次小事務,可降低 FE 的 Edit Log 寫入頻率(減少元數據操作)及 BE 的 MemTable 刷盤次數(減少小文件生成),避免存儲碎片和後續 Compaction 的資源消耗。

  • 服務端攢批(Group Commit):合併小事務,優化存儲效率

開啓 Group Commit 後,服務端將短時間內的多個小批量導入合併為單一事務,減少 Edit Log 寫入次數和 MemTable 刷盤頻率。合併後的大事務生成更大的 Segment 文件(減少小文件),減輕後台 Compaction 壓力,特別適用於高頻小批量場景(如日誌、IoT 數據寫入)。

分桶數優化:平衡負載與分發效率

分桶數決定 Tablet 數量(每個桶對應一個 Tablet),直接影響數據在 BE 節點的分佈。過少分桶易導致數據傾斜(單 BE 負載過高),過多分桶會增加元數據管理和分發開銷(BE 需處理更多 Tablet 的 MemTable 和 Segment 文件)。

  • 合理配置分桶數:確保 Tablet 大小均衡

分桶數需根據 BE 節點數量和數據量設置,推薦單 Tablet 壓縮後的數據大小為 1-10GB(計算公式:分桶數=總數據量/(1-10GB))。同時,調整分桶鍵(如隨機數列)避免數據傾斜。合理分桶可平衡 BE 節點負載,避免單節點過載或多節點資源浪費,提升並行寫入效率。

  • 隨機分桶優化:減少 RPC 開銷與 Compaction 壓力

在隨機分桶場景中,啓用load_to_single_tablet=true,可將數據直接寫入單一 Tablet,繞過分發到多個 Tablet 的過程。這消除了計算 Tablet 分佈的 CPU 開銷和 BE 間的 RPC 傳輸開銷,顯著提升寫入速度。同時,集中寫入單一 Tablet 減少了小 Segment 文件的生成,避免頻繁 Compaction 帶來的寫放大,降低減少 BE 的資源消耗和存儲碎片,提升導入和查詢效率。

內存優化:減少刷盤與資源衝擊

數據導入時,BE 先將數據寫入內存的 MemTable(默認 200MB),寫滿後異步刷盤生成 Segment 文件(觸發磁盤 I/O)。高頻刷盤會增加磁盤或對象存儲(存算分離場景)的 I/O 壓力;內存不足則導致 MemTable 分散(多分區/分桶時),易觸發頻繁刷盤或 OOM。

  • 按分區順序導入:集中內存使用

按分區順序(如逐天)導入,集中數據寫入單一分區,減少 MemTable 分散(多分區需為每個分區分配 MemTable)和刷盤次數,降低內存碎片和 I/O 壓力。

  • 大規模數據分批導入:降低資源衝擊

對大文件或多文件導入(如 Broker Load),建議分批(每批≤100GB),避免導入出錯後帶來過大的重試代價過大,同時減少對 BE 內存和磁盤的集中佔用。本地大文件可使用streamloader工具自動分批導入。

併發優化:平衡吞吐量與資源競爭

Doris 的分佈式架構支持多 BE 並行寫入,增加併發可提升吞吐量,但過高併發會導致 CPU、內存或對象存儲 QPS 爭搶(存算分離場景需考慮 S3 等 API 的 QPS 限制),會增加事務衝突和延遲。

  • 合理控制併發:匹配硬件資源

結合 BE 節點數和硬件資源(CPU、內存、磁盤 I/O)設置併發線程。適度併發可充分利用 BE 並行處理能力,提升吞吐量;過高併發則因資源爭搶降低效率。

  • 低時延場景:降低併發與異步提交

對低時延要求場景(如實時監控),需降低併發數(避免資源競爭),並結合 Group Commit 的異步模式(async_mode)合併小事務,減少事務提交延遲。

Doris 數據導入的延遲與吞吐取捨

在使用 Apache Doris 時,數據導入的 延遲(Latency)吞吐量(Throughput) 往往需要在實際業務場景中進行平衡:

  • 更低延遲:意味着用户能更快看到最新數據,但寫入批次更小,寫入頻率更高,會導致後台 Compaction 更頻繁,佔用更多 CPU、IO 和內存資源,同時增加元數據管理的壓力。
  • 更高吞吐:則通過增大單次導入數據量來減少導入次數,可以顯著降低元數據壓力和後台 Compaction 開銷,從而提升系統整體性能。但數據寫入到可見之間的延遲會有所增加。

因此,建議用户在滿足業務時延要求的前提下,儘量增大單次導入寫入的數據量,以提升吞吐並減少系統開銷。

測試數據

Flink 端到端時延

採用 Flink Connector 使用攢批模式進行寫入,主要關注數據端到端的時延和導入吞吐。攢批時間通過 flink Connector 的 sink.buffer-flush.interval 參數來控制的,Flink Connector 的詳細使用參考:https://doris.apache.org/docs/3.0/ecosystem/flink-doris-conne...

機器配置:

  • 1 台 FE: 8 核 CPU、16GB 內存
  • 3 台 BE:16 核 CPU、64GB 內存

數據集:

  • TPCH lineitem 數據

不同攢批時間和不同併發下的導入性能,測試結果如下:

TPCH lineitem 測試數據-1.jpg

不同 bucket 數對導入性能的影響,測試結果如下:

TPCH lineitem 數據-2.jpg

Group Commit 測試

性能測試數據參考:https://doris.apache.org/zh-CN/docs/3.0/data-operate/import/g...

總結

Apache Doris 的數據導入優化並非單一參數的調整,而是一個涉及表結構設計、寫入策略、資源配置與業務場景的系統性工程。 數據導入機制依託 FE 和 BE 的分佈式協作,結合事務管理和輕量 ETL 功能,來確保高效、可靠的數據寫入。頻繁小批量導入會增加事務開銷、存儲碎片和 Compaction 壓力,可以通過以下優化策略來有效緩解:

  • 表結構設計:合理分區和明細模型減少掃描和計算開銷,精簡索引降低寫入負擔。
  • 攢批優化:客户端和服務端攢批減少事務和 flush 頻率,生成大文件,優化存儲和查詢。
  • 分桶數優化:適量分桶平衡負載,避免熱點或管理開銷。
  • 內存優化:控制 MemTable 大小、按分區導入。
  • 併發優化:適度併發提升吞吐量,結合分批和資源監控控制延遲。

用户可根據業務場景(如實時日誌、批量 ETL)結合這些策略,優化表設計、參數配置和資源分配,可以顯著提升導入性能。

user avatar u_16640205 頭像 u_17569005 頭像 huikaichedemianbao 頭像 pannideniupai 頭像 feibendemaojin 頭像 data_ai 頭像 dcsjava 頭像 fennudebiandang 頭像 doge_king 頭像 nbidashuju 頭像 chenzhuodeyagao 頭像 bizidadejianbing 頭像
點贊 20 用戶, 點贊了這篇動態!
點贊

Add a new 評論

Some HTML is okay.