Apache Hudi 後設資料欄位揭祕

2023-07-01 18:01:21

介紹

Apache Hudi 最初由Uber於 2016 年開發,旨在實現一個交易型資料湖,該資料湖可以快速可靠地支援更新,以支援公司拼車平臺的大規模增長。 Apache Hudi 現在被業內許多人廣泛用於構建一些非常大規模的資料湖。 Apache Hudi 為快速變化的環境中管理資料提供了一個有前途的解決方案。

Hudi 使使用者能夠使用 Hudi 儲存的記錄級後設資料跟蹤單個記錄隨時間的變化,這是 Hudi 的基本設計選擇。 然而,由於這種選擇在同行中的獨特性,因此也是引起爭議的常見原因,並且清楚地瞭解記錄級後設資料提供的價值以及額外成本至關重要。 本部落格將討論 Hudi 中五個記錄級元欄位的重要性以及相關的儲存開銷,以充分理解其對 Apache Hudi 工作負載的好處。

_hoodie_record_key 元欄位

記錄鍵元欄位用於唯一標識 Hudi 表或分割區中的記錄。 藉助記錄鍵,Hudi 可以確保沒有重複記錄,並在寫入時強制執行唯一性完整性約束。 與資料庫類似,記錄鍵也用於記錄的索引,以實現更快、有針對性的更新和刪除,以及從 Hudi 表生成 CDC 更改紀錄檔。 大多數源資料已經包含一個自然記錄鍵,儘管 Hudi 也可以自動生成記錄鍵(即將釋出),以支援紀錄檔事件等可能不包含此類欄位的用例。

需要定義記錄鍵

在可變工作負載中,資料在被攝取或儲存後會發生變化。 通常這些是 a) 刪除請求以符合資料保護相關法規和 b) 從上游系統向下傳遞的更新請求。 如果沒有記錄鍵將更改記錄連結在一起,可能會導致系統中出現重複記錄。 例如,假設我們正在從上游 OLTP 資料庫接收變更紀錄檔。 這些紀錄檔可以在一個時間視窗內多次更新同一個主鍵。 為了防止重複,我們必須合併同一提交中的記錄,並根據相同的鍵定義始終如一地針對儲存中的記錄進行合併。

如果想知道記錄鍵對不可變資料不是很有幫助,讓我們舉個例子。 考慮這樣一個場景,新資料不斷新增到表中,同時需要回填來修復過去的資料質量問題或推出新的業務邏輯。 回填可以在任何時間段發生,並且不能保證被回填的資料不會與活動寫入重疊。 如果沒有記錄鍵,回填必須嚴格逐個分割區執行,同時與寫入端協調以遠離回填分割區以避免不準確的資料或重複。 但是使用記錄鍵,使用者可以識別和回填單個記錄,而不是在較粗略的分割區級別處理它。 當結合 Hudi 的並行控制機制和對排序欄位的支援時,正常和回填寫入端可以無縫寫入表,而不必擔心回填寫入端覆蓋正常寫入,這可以使表恢復到舊狀態。 請注意即使使用嚴格序列化的事務,這些事情也可能發生在資料上。

需要具體化記錄鍵

現在已經確定我們需要記錄鍵,讓我們瞭解為什麼它們還需要以持久形式與實際記錄一起儲存,即使 Hudi 支援虛擬鍵。 這樣做有明顯的好處,在複合鍵的情況下,每次重新計算或重新處理記錄鍵可能很耗時,因為它需要從儲存中讀取多個列。 故障時有發生,在資料工程中,設定的無意變更很常見,通常會導致多個團隊花費數小時來確定和解決根本原因。 這方面的一個例子可能是記錄鍵設定被意外更改,導致兩條記錄看似重複,但在系統中被視為單獨的記錄。 當關鍵欄位發生變化時(比如從 A 到 B),無法保證表中的所有歷史資料相對於新的關鍵欄位 B 都是唯一的,因為到目前為止我們已經對 A 執行了所有唯一性實施。 因此實現記錄鍵是一種簡單而有效的技術,可以避免陷入這些棘手的資料質量問題。 如果使用物化記錄鍵,則兩個記錄之間的差異(記錄鍵的更改)與資料一起記錄,並且不會違反唯一性約束。

啟用記錄鍵的功能

資料庫通常由多個內部元件組成,它們協同工作以向用戶提供效率、效能和出色的可操作性。 同樣 Hudi 也設計了內建的表服務和索引機制,以確保高效能的表儲存佈局和更快的查詢。

這些服務依靠記錄鍵來正確有效地實現其預期目標。 讓我們以壓縮服務為例。 壓縮是一種將增量紀錄檔與基本檔案合併以生成具有最新資料快照的最新版本檔案的方法。 壓縮過程每次都檢查資料以提取舊檔案的記錄鍵是低效的。 反序列化成本很容易增加,因為這需要對每條記錄以及每次執行壓縮時進行。 正如開創性的資料庫工作所指出的那樣,記錄鍵是將加快寫入/查詢速度的索引等技術與導致記錄在表內跨檔案移動的聚簇等其他機制聯絡在一起的基本結構。

_hoodie_partition_path 和 _hoodie_file_name 元欄位

這些欄位捕獲 Hudi 表中記錄的物理/空間分佈。 _hoodie_partition_path 欄位表示記錄存在的相對分割區路徑。 _hoodie_file_name 欄位表示存在記錄的實際資料檔名。 回到Hudi增量資料處理的根源,分割區路徑欄位通常用於從增量查詢進一步過濾記錄,例如下游ETL作業只對表中最後N天分割區的變化感興趣,可以通過簡單地編寫一個 _hoodie_partition_path 過濾器實現。

這些欄位也是在生產環境中快速偵錯資料質量問題的手段。 想象一下偵錯重複記錄問題,這是由重複作業或鎖提供程式設定錯誤等引起的。注意到表中有重複條目但不確定它們是如何出現的。 還需要找到受影響的記錄並確定問題發生的時間。 如果沒有必要的元欄位,確定問題的根本原因就像大海撈針。 在 Hudi 中,簡單的 "select _hoodie_partition_path, _hoodie_file_name, columns from <hudi_table> where ;" 將選取分割區路徑和檔名,從中提供重複記錄以進一步調查。 由於這兩個欄位對於單個檔案中的所有記錄都是相同的,因此它們壓縮得很好並且不承擔任何開銷。

_hoodie_commit_seqno 和 _hoodie_commit_time 元欄位

這兩個欄位代表一條記錄在Hudi表中的時間分佈,從而可以跟蹤記錄的變化歷史。 _hoodie_commit_time 欄位表示建立記錄時的提交時間,類似於資料庫提交。 _hoodie_commit_seqno 欄位是提交中每條記錄的唯一序列號,類似於 Apache Kafka 主題中的偏移量。 在 Kafka 中偏移量幫助流式使用者端跟蹤訊息並在發生故障或關閉後從同一位置恢復處理。 同樣,_hoodie_commit_seqno 可用於從 Hudi 表生成流。

記錄級別更改跟蹤

為了更好地理解此功能,讓我們考慮一個寫入時複製 (CoW) 表,其中新的寫入通過與現有的最新基礎檔案合併來生成版本化的基礎檔案。 僅在此處跟蹤檔案級別的版本可能是不夠的,因為並非檔案中的所有記錄在提交期間都已更新。 要在其他LakeHouse系統中獲得這種型別的記錄級更改,必須連線表的每兩個相鄰快照,這在丟失有關錶快照的後設資料等情況下可能非常昂貴且不精確。

相比之下 Hudi 將記錄級別的變更流視為首要設計目標,並在所有級別對這些資訊進行編碼——將時間提交到檔案、紀錄檔塊和記錄中。 此外通過將這種更改跟蹤資訊與資料一起有效地儲存,即使是增量查詢也可以從在表上執行的所有儲存組織/排序/佈局優化中受益。

近乎無限的時間旅行

Hudi 使用此元欄位解鎖的另一個強大功能是能夠為記錄保留近乎無限的歷史記錄。 Hudi 社群的一位使用者——一家大型銀行,能夠成功利用此功能支援對歷史資料的時間旅行查詢——甚至可以追溯到 5 或 6 年前。 這可以在實踐中通過僅管理檔案大小設定、啟用可延伸後設資料和禁用清理器來實現。 如果不將提交時間與記錄一起儲存,就不可能從記錄建立時就看到記錄的歷史記錄。 當想在擁有這麼多年資料的歷史表中挖掘時間旅行能力時這個功能就派上用場了。

結合 Hudi 的可延伸表後設資料,這可以解鎖近乎無限的歷史保留,這使得一些 Hudi 使用者甚至可以回到幾年前。

後設資料欄位開銷

到目前為止我們討論了 Hudi 中元欄位解鎖的基本功能。 如果仍然擔心元欄位的儲存成本,我們想以一個小的基準估計此開銷。 這個基準測試是基於 Hudi master 執行的。 為此我們為不同寬度的表格生成了樣本資料,並比較了在 Hudi 表格中儲存額外元欄位與通過 spark 編寫的普通Parquet表的成本。如果對細節感興趣,這裡是基準設定。

該基準測試在三種不同寬度(10 列、30 列和 100 列)的表格上比較了 Vanilla Parquet、具有預設 gzip 壓縮的 Hudi CoW Bulk Insert 和具有 snappy 壓縮的 Hudi CoW Bulk Insert。 Hudi 預設使用 gzip 壓縮,這比 Vanilla Spark Parquet 編寫的壓縮效果更好。可以看到包括後設資料在內的實際資料被很好地壓縮(記錄鍵元欄位壓縮 11 倍,而其他壓縮甚至更多,有時甚至完全壓縮)並且與沒有元欄位的Vanilla Parquet資料相比儲存更少。 Hudi 的預設設定是在未來的版本中轉向 zstd,這將抵消 gzip 相對於 snappy 的計算開銷。 即使我們在 Hudi 中使用 snappy 編解碼器也可以看到隨著表變得越來越寬,為 100 TB 表估計的元欄位佔用的額外空間會減少。 即使對於標準 TPCDS 上的 100 TB 表大小(例如具有 30 列的表),也只需支付約 8 美元即可新增記錄級元欄位。 如果表格更寬比如 100 列甚至 1000 列,新增元欄位的成本不會超過 1 美元。

結論

總之 Hudi 在記錄級別跟蹤的元欄位具有更大的用途。 它們通過保持表中的唯一性約束、支援更快的目標更新/刪除、實現增量處理和時間旅行、支援表服務準確高效地執行、安全地處理重複項、時間旅行,在維護資料完整性方面發揮著關鍵作用。它們有助於偵錯並防止由於潛在的資料質量問題而導致的管道清理噩夢。 如果使用像 Delta 或 Iceberg 這樣沒有這些元欄位的表格格式,那麼其中許多好處並不容易實現。 例如像重複檢測這樣基本的事情需要與源資料和資料模型的假設進行多次連線,或者由使用者負責在將其引入資料湖之前進行處理。 在我們結束之前,我們希望讀者考慮這個問題 - 為靜態大小為 100TB 的 30 列表新增元欄位的成本約為 8 美元就可以享受記錄級元欄位提供的好處。

如果仍然不確定,請檢視 Uber 的這篇部落格。 Uber 利用 Hudi 紀錄的元欄位和增量處理能力的組合,將其管道中的計算成本降低了 80%,這可以輕鬆覆蓋額外的元欄位開銷,數倍於此。