作者:羅一鑫 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 → 寫入對象存儲”。
這種大導入路徑的優化,主要在三個方面帶來了顯著收益:
- 當 memtable 寫滿時,系統僅將中間結果 spill 到本地磁盤,而不直接寫入後端對象存儲,從而顯著提升了這一階段的寫入性能。
- 同時在 spill 階段,只需將 memtable 中的數據快速落盤,無需執行完整的數據排序、編碼、索引構建等操作帶來的額外資源開銷。
- 中間階段產生的臨時文件會在最終落盤前統一 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 對比
可以看到,在開啓該優化後:
- 對 S3 的寫入次數顯著減少,寫吞吐顯著提高,單個對象的平均大小大幅提升,有利於降低存儲成本並提升整體讀寫性能;
- 導入過程能夠更加充分地利用本地磁盤的 I/O 能力,從而帶來明顯的導入性能提升。
總結
通過在內核層面優化批量數據導入能力,StarRocks 在歷史數據回灌場景下有效避免了資源(尤其是內存)受限時產生的大量小文件問題,也讓用户能夠在存算分離架構下以更低的投入,獲得更高效、更穩定的使用體驗。