Apache Hudi 元數據字段揭祕

介紹

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%,這可以輕鬆覆蓋額外的元字段開銷,數倍於此。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章