一文徹底理解Apache Hudi的多版本清理服務

leesf 發表於 2021-06-17

Apache Hudi提供了MVCC併發模型,保證寫入端和讀取端之間快照級別隔離。在本篇部落格中我們將介紹如何配置來管理多個檔案版本,此外還將討論使用者可使用的清理機制,以瞭解如何維護所需數量的舊檔案版本,以使長時間執行的讀取端不會失敗。

1. 回收空間以控制儲存成本

Hudi 提供不同的表管理服務來管理資料湖上表的資料,其中一項服務稱為Cleaner(清理服務)。 隨著使用者向表中寫入更多資料,對於每次更新,Hudi會生成一個新版本的資料檔案用於儲存更新後的記錄(COPY_ON_WRITE) 或將這些增量更新寫入日誌檔案以避免重寫更新版本的資料檔案 (MERGE_ON_READ)。 在這種情況下,根據更新頻率,檔案版本數可能會無限增長,但如果不需要保留無限的歷史記錄,則必須有一個流程(服務)來回收舊版本的資料,這就是 Hudi 的清理服務。

2. 問題描述

在資料湖架構中,讀取端和寫入端同時訪問同一張表是非常常見的場景。由於 Hudi 清理服務會定期回收較舊的檔案版本,因此可能會出現長時間執行的查詢訪問到被清理服務回收的檔案版本的情況,因此需要使用正確的配置來確保查詢不會失敗。

3. 深入瞭解 Hudi清理服務

針對上述場景,我們先了解一下 Hudi 提供的不同清理策略以及需要配置的相應屬性,Hudi提供了非同步或同步清理兩種方式。在詳細介紹之前我們先解釋一些基本概念:

  • Hudi 基礎檔案(HoodieBaseFile):由壓縮後的最終資料組成的列式檔案,基本檔案的名稱遵循以下命名約定:<fileId>_<writeToken>_<instantTime>.parquet。在此檔案的後續寫入中檔案 ID 保持不變,並且提交時間會更新以顯示最新版本。這也意味著記錄的任何特定版本,給定其分割槽路徑,都可以使用檔案 ID 和 instantTime進行唯一定位。
  • 檔案切片(FileSlice):在 MERGE_ON_READ 表型別的情況下,檔案切片由基本檔案和由多個增量日誌檔案組成。
  • Hudi 檔案組(FileGroup):Hudi 中的任何檔案組都由分割槽路徑和檔案ID 唯一標識,該組中的檔案作為其名稱的一部分。檔案組由特定分割槽路徑中的所有檔案片組成。此外任何分割槽路徑都可以有多個檔案組。

4. 清理服務

Hudi 清理服務目前支援以下清理策略:

  • KEEP_LATEST_COMMITS:這是預設策略。該清理策略可確保回溯前X次提交中發生的所有更改。假設每 30 分鐘將資料攝取到 Hudi 資料集,並且最長的執行查詢可能需要 5 小時才能完成,那麼使用者應該至少保留最後 10 次提交。通過這樣的配置,我們確保檔案的最舊版本在磁碟上保留至少 5 小時,從而防止執行時間最長的查詢在任何時間點失敗,使用此策略也可以進行增量清理。
  • KEEP_LATEST_FILE_VERSIONS:此策略具有保持 N 個檔案版本而不受時間限制的效果。當知道在任何給定時間想要保留多少個 MAX 版本的檔案時,此策略很有用,為了實現與以前相同的防止長時間執行的查詢失敗的行為,應該根據資料模式進行計算,或者如果使用者只想維護檔案的 1 個最新版本,此策略也很有用。

5. 例子

假設使用者每 30 分鐘將資料攝取到 COPY_ON_WRITE 型別的 Hudi 資料集,如下所示:

一文徹底理解Apache Hudi的多版本清理服務

圖1:每30分鐘將傳入的記錄提取到hudi資料集中

該圖顯示了 DFS 上的一個特定分割槽,其中提交和相應的檔案版本是彩色編碼的。在該分割槽中建立了 4 個不同的檔案組,如 fileId1、fileId2、fileId3 和 fileId4 所示。 fileId2 對應的檔案組包含所有 5 次提交的記錄,而 fileId4 對應的組僅包含最近 2 次提交的記錄。

假設使用以下配置進行清理:

hoodie.cleaner.policy=KEEP_LATEST_COMMITS
hoodie.cleaner.commits.retained=2

Cleaner 通過處理以下事項來選擇要清理的檔案版本:

  • 不應清理檔案的最新版本。
  • 確定最後 2 次(已配置)+ 1 次提交的提交時間。在圖 1 中,commit 10:30commit 10:00 對應於時間線中最新的 2 個提交。包含一個額外的提交,因為保留提交的時間視窗本質上等於最長的查詢執行時間。因此如果最長的查詢需要 1 小時才能完成,並且每 30 分鐘發生一次攝取,則您需要保留自 2*30 = 60(1 小時)以來的最後 2 次提交。此時最長的查詢仍然可以使用以相反順序在第 3 次提交中寫入的檔案。這意味著如果一個查詢在 commit 9:30 之後開始執行,當在 commit 10:30 之後觸發清理操作時,它仍然會執行,如圖 2 所示。
  • 現在對於任何檔案組,只有那些沒有儲存點(另一個 Hudi 表服務)且提交時間小於第 3 次提交(下圖中的“提交 9:30”)的檔案切片被清理。

一文徹底理解Apache Hudi的多版本清理服務

圖2:保留最近3次提交對應的檔案

假設使用以下配置進行清理:

hoodie.cleaner.policy=KEEP_LATEST_FILE_VERSIONS
hoodie.cleaner.fileversions.retained=1

清理服務執行以下操作:

  • 對於任何檔案組,檔案切片的最新版本(包括任何待壓縮的)被保留,其餘的清理掉。 如圖 3 所示,如果在 commit 10:30 之後立即觸發清理操作,清理服務將簡單地保留每個檔案組中的最新版本並刪除其餘的。

一文徹底理解Apache Hudi的多版本清理服務

圖3:保留每個檔案組中的最新檔案版本

6. 配置

可以在 此處 中找到有關所有可能配置的詳細資訊以及預設值。

7. 執行命令

Hudi 的清理表服務可以作為單獨的程式執行,可以與資料攝取一起執行。正如前面提到的,它會清除了任何陳舊檔案。如果您想將它與攝取資料一起執行,可以使用配置同步或非同步執行。或者可以使用以下命令獨立執行清理服務:

[hoodie]$ spark-submit --class org.apache.hudi.utilities.HoodieCleaner \
  --props s3:///temp/hudi-ingestion-config/config.properties \
  --target-base-path s3:///temp/hudi \
  --spark-master yarn-cluster

如果您希望與寫入非同步執行清理服務,可以配置如下內容:

hoodie.clean.automatic=true
hoodie.clean.async=true

此外還可以使用 Hudi CLI 來管理 Hudi 資料集。CLI 為清理服務提供了以下命令:

  • cleans show
  • clean showpartitions
  • clean run

可以在 org.apache.hudi.cli.commands.CleansCommand 中找到這些命令的更多詳細資訊和相關程式碼。

8. 未來計劃

目前正在進行根據已流逝的時間間隔引入新的清理策略,即無論攝取發生的頻率如何,都可以保留想要的檔案版本,可以在 此處 跟蹤進度。

我們希望這篇部落格能讓您瞭解如何配置 Hudi 清理服務和支援的清理策略。請訪問部落格部分 以更深入地瞭解各種 Hudi 概念。