博客 / 詳情

返回

從小文件困局到“花小錢辦大事”:StarRocks 存算分離批量導入優化實踐

作者:羅一鑫 StarRocks Committer

導讀:在存算分離架構下,“一次性導入海量歷史數據”正成為被放大的隱形風險。本文介紹 StarRocks 如何從寫入源頭重構大導入路徑:通過“內存→本地磁盤 spill→集中 merge→對象存儲”,減少遠程寫入和重複開銷,降低 S3 寫入次數並放大文件粒度,釋放本地 I/O 能力,從源頭緩解小文件問題,幫助用户以更低投入獲得更高效、更穩定的使用體驗。

大規模導入,在存算分離架構下變成“放大問題”

在越來越多用户將歷史數據整體遷移至 StarRocks 的過程中,“一次性導入海量歷史數據”逐漸成為常見操作場景。表面上看,這只是一次離線灌庫任務;但在存算分離 + 對象存儲的架構下,如果處理不當,很容易引發導入效率下降、底層小文件激增、查詢性能受損等一連串連鎖反應。

StarRocks 作為一款分佈式列式數據庫,底層採用類似 LSM-Tree 的存儲結構:新寫入的數據首先進入內存中的 memtable,經排序等處理後再由後台線程刷盤至持久化存儲,並通過後續的 Compaction 將多個小文件合併為更大的有序文件。在常規規模的增量寫入下,這套機制可以很好地兼顧寫入性能與查詢性能;但在大批量導入歷史數據時,問題會被顯著放大:

  • 歷史數據量巨大、涉及 Tablet 數量多。每個 Tablet 維護獨立的 memtable,在高併發導入的壓力下,系統會頻繁將 memtable 刷盤,短時間內生成大量的小文件。
  • 在存算分離架構下,計算與存儲解耦,用户往往會從較少數量、較小規格的 CN 節點開始使用集羣(甚至僅有 1 個 CN 節點),有限的 CPU 和內存進一步加劇了“小 memtable、頻繁刷盤、小文件堆積”的問題。
  • 存算分離讓用户可以在完成批量導入後快速縮容或釋放計算節點,僅保留對象存儲中的數據以節約成本。但這也意味着導入階段產生的大量小文件沒有得到及時、充分的合併整理,底層存儲中會長期殘留數量眾多的小文件。
  • 當用户再次拉起集羣對這些歷史數據進行查詢時,需要掃描和處理的大量小文件會顯著拉低查詢性能。

可以看到,這些問題在存算分離架構中更為突出,本質原因在於:用户更傾向於使用少量、小規格的計算節點來完成大規模歷史數據導入,這一選擇會導致小文件氾濫、進而導致查詢性能受損等問題。

從寫入源頭下手,重構大導入路徑

要想真正解決“大導入引發的小文件問題”,僅依靠後續的 Compaction 合併文件遠遠不夠。通過對整個寫入鏈路的分析可以發現,問題的根源主要集中在以下幾個方面:

  • 受限於內存,CN 節點往往在 memtable 尚未寫滿時就被迫刷盤,單次刷盤生成的文件體積偏小;
  • 在存算分離架構下,每次刷盤都需要直接寫入對象存儲,高延遲的遠程 I/O 疊加頻繁寫入,使導入效率大幅下降;
  • 每一次落盤都伴隨數據排序、編碼、壓縮以及索引構建等完整寫入流程,頻繁重複這些工作會消耗大量 CPU 資源;
  • 最終,這些過多、過小的文件還需要再次被讀取參與 Compaction 合併,前期投入的排序、編碼等工作在一定程度上變成了“無用功”,進一步浪費系統資源。

基於上述分析,StarRocks 在存算分離場景下重新設計了大導入的寫路徑,從源頭對寫入流程進行優化:

  • 寫入階段:優先 Spill 到本地磁盤當 memtable 寫滿時,不再直接將數據寫入對象存儲,而是通過 spill 能力將中間數據緩存在 CN 本地磁盤。這樣既避免了高延遲的對象存儲寫入,也避免了在尚未穩定成型之前就反覆進行排序、編碼等“重工作”。在本地磁盤空間不足時,中間數據也可以有選擇地溢寫到 S3 等對象存儲中,保證整體流程的穩定性。
  • 收斂階段:集中 Merge 後再寫入對象存儲 當本次大導入任務的數據全部寫入完成後,系統再對上述 spill 生成的臨時文件進行集中 merge,將其整理為結構合理、粒度適中的目標數據文件,最終寫入對象存儲。

整體來看,新的大導入路徑可以概括為:“內存 → 本地磁盤 Spill → 集中 Merge → 寫入對象存儲”

這種大導入路徑的優化,主要在三個方面帶來了顯著收益:

  1. 當 memtable 寫滿時,系統僅將中間結果 spill 到本地磁盤,而不直接寫入後端對象存儲,從而顯著提升了這一階段的寫入性能。
  2. 同時在 spill 階段,只需將 memtable 中的數據快速落盤,無需執行完整的數據排序、編碼、索引構建等操作帶來的額外資源開銷。
  3. 中間階段產生的臨時文件會在最終落盤前統一 merge,整合成數量更少、粒度更大的目標文件寫入對象存儲。這樣一方面顯著減少了底層小文件數量,幾乎不再依賴額外的後台 Compaction 來來進行合併;另一方面,即使在導入完成後立即發起查詢,也能獲得穩定的性能表現。

效果對比

為了評估上述大導入優化在真實場景下的收益,我們在存算分離集羣上設計了兩組對比測試:

  • 單併發場景:單個導入任務,導入 1 TB 數據,對比優化前後的導入耗時及導入完成後的查詢性能;
  • 多併發壓力場景:10 個併發導入任務,每個導入 100 GB(總量同樣為 1 TB),對比優化前後的導入性能以及導入完成後的查詢表現。

測試一:單併發大數據集導入

在這一測試中,我們使用 Broker Load 以單併發方式一次性導入 1 TB 數據集(約 2.7 億行)。在優化前,導入階段耗時約 2 小時 15 分鐘,此後系統又花費約 34 分鐘完成後台 Compaction。從用户視角看,從提交導入任務到系統恢復為穩定可查詢狀態,總耗時約 2 小時 50 分鐘。

*************************** 3. row ***************************
         JobId: 10409
         State: FINISHED
          Type: BROKER
      SinkRows: 270000000
 LoadStartTime: 2024-12-27 10:59:12
LoadFinishTime: 2024-12-27 13:14:04

導入完成後,該分區的 compaction score:

AvgCS: 358.06    P50CS: 299.00    MaxCS: 1056.00

當導入完成後立即發起如下查詢:

mysql> select count(*) from duplicate_21_0;
+-----------+
| count(*)  |
+-----------+
| 270000000 |
+-----------+
1 row in set (56.25 sec)

優化後,導入總計耗時約 2h 42min

*************************** 2. row ***************************
         JobId: 10642
         State: FINISHED
          Type: BROKER
      SinkRows: 270000000
 LoadStartTime: 2024-12-27 16:14:08
LoadFinishTime: 2024-12-27 18:56:00

導入完成後,compaction score 已經是最佳值,無需後台合併:

AvgCS: 2.39    P50CS: 2.00    MaxCS: 5.00

導入完成後立刻發起查詢:

mysql> select count(*) from duplicate_21_0;
+-----------+
| count(*)  |
+-----------+
| 270000000 |
+-----------+
1 row in set (0.72 sec)

測試二:多併發大數據集壓力測試

在這一測試中,對總量 1 TB 的數據進行多併發導入壓力測試,目標表共包含 28 個 partition,每個 partition 下有 256 個 tablet。在優化前,受限於單個集羣節點的 CPU 和內存資源,導入始終無法在 4 小時的超時時間內完成,最終被系統自動取消,任務狀態如圖所示:

*************************** 10. row ***************************
         JobId: 11458
         State: CANCELLED
          Type: BROKER
      Priority: NORMAL
      ScanRows: 21905408
 LoadStartTime: 2025-01-06 17:11:46
LoadFinishTime: 2025-01-06 21:11:44

而在優化後:

*************************** 20. row ***************************
         JobId: 28336
         State: FINISHED
          Type: BROKER
      Priority: NORMAL
      ScanRows: 30000000
LoadStartTime:  2025-01-06 20:10:49
LoadFinishTime: 2025-01-06 20:27:59

在相同場景下,10 個併發導入任務從 2025-01-06 20:10:49 開始,到 2025-01-06 20:36:10 全部完成,總耗時約 25 分鐘。

這 10 個導入任務剛好觸發了 Compact 閾值,但導入結束時系統的 compaction score 始終保持在較為理想的區間:

AvgCS: 10.00    P50CS: 10.00    MaxCS: 10.00

另外,可以觀察後端對象存儲在優化前後的一些關鍵指標:

優化前 S3 關鍵指標

優化後 S3 關鍵指標

優化前後 Local Disk IO Util 對比

可以看到,在開啓該優化後:

  1. 對 S3 的寫入次數顯著減少,寫吞吐顯著提高,單個對象的平均大小大幅提升,有利於降低存儲成本並提升整體讀寫性能;
  2. 導入過程能夠更加充分地利用本地磁盤的 I/O 能力,從而帶來明顯的導入性能提升。

總結

通過在內核層面優化批量數據導入能力,StarRocks 在歷史數據回灌場景下有效避免了資源(尤其是內存)受限時產生的大量小文件問題,也讓用户能夠在存算分離架構下以更低的投入,獲得更高效、更穩定的使用體驗。

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.