記錄級別索引:Hudi 針對大型數據集的超快索引

介紹

索引是一個關鍵組件,有助於 Hudi 寫入端快速更新和刪除,並且它在提高查詢執行方面也發揮着關鍵作用。 Hudi提供了多種索引類型,包括全局變化的Bloom索引和Simple索引、利用HBase服務的HBase索引、基於哈希的Bucket索引以及通過元數據表實現的多模態索引。 索引的選擇取決於表大小、分區數據分佈或流量模式等因素,其中特定索引可能更適合更簡單的操作或更好的性能。 用戶在爲不同表選擇索引類型時經常面臨權衡,因爲還沒有一種能夠以最小的操作開銷促進寫入和讀取的通用性能索引。

從 Hudi 0.14.0 開始,我們很高興地宣佈 Apache Hudi 的通用索引 - 記錄級別索引 (RLI)。 這一創新不僅顯着提高了寫入效率,還提高了相關查詢的讀取效率。 RLI 無縫集成在表存儲層中,無需任何額外的操作工作即可輕鬆工作。

在本博客的後續部分中,我們將簡要介紹 Hudi 的元數據表,這是討論 RLI 的先決條件。 接下來我們將深入研究 RLI 的設計和工作流程,然後展示性能分析和索引類型比較。 該博客將以對 RLI 未來工作作爲結尾。

元數據表

Hudi 元數據表.hoodie/metadata/ 目錄中的讀取合併 (MoR) 表。 它包含與記錄相關的各種元數據,無縫集成到寫入器和讀取器路徑中,以提高索引效率。 元數據分爲四個分區:文件、列統計信息、布隆過濾器和記錄級索引。

元數據表與時間軸上的每個提交操作同步更新,換句話說,對元數據表的提交是對Hudi數據表的事務的一部分。 通過包含不同類型元數據的四個分區,此佈局可實現多模式索引的目的:

  • files分區跟蹤Hudi數據表的分區,以及每個分區的數據文件
  • column stats分區記錄了數據表每一列的統計信息
  • bloom filter分區存儲基本文件的序列化布隆過濾器
  • record level index分區包含各個記錄鍵和相應文件組ID的映射

用戶可以通過設置 hoodie.metadata.enable=true 來啓用元數據表。 一旦啓用,文件分區將始終啓用。 可以單獨啓用和配置其他分區以利用額外的索引功能。

記錄級別索引

從版本 0.14.0 開始,可以通過設置 hoodie.metadata.record.index.enable=truehoodie.index.type=RECORD_INDEX 來激活記錄級別索引 (RLI)。 RLI 背後的核心概念是能夠確定記錄的位置,從而減少需要掃描以提取所需數據的文件數量。 這個過程通常被稱爲“索引查找”。 Hudi 採用主鍵模型,要求每個記錄與一個鍵關聯以滿足唯一性約束。 因此我們可以在記錄鍵和文件組之間建立一對一的映射,這正是我們打算在記錄級索引分區中存儲的數據。

對於索引而言,性能至關重要。 包含RLI分區的元數據表選擇HFile作爲文件格式,HBase的文件格式利用B+樹結構進行快速查找。 現實工作負載的基準測試表明,包含 100 萬個 RLI 映射的 HFile 可以在 600 毫秒內查找一批 100k 記錄。 我們將在後面的部分中介紹性能主題並進行詳細分析。

初始化

爲現有 Hudi 表初始化 RLI 分區可能是一項費力且耗時的任務,具體取決於記錄的數量。 就像典型的數據庫一樣,構建索引需要時間,但最終會通過加速未來的大量查詢而得到回報。

上圖顯示了 RLI 初始化的步驟。 由於這些作業都是可並行的,因此用戶可以相應地擴展集羣並配置相關的並行設置(例如 hoodie.metadata.max.init.parallelism)以滿足他們的時間要求。

重點關注最後一步“批量插入到 RLI 分區”,元數據表寫入端使用哈希函數對 RLI 記錄進行分區,確保生成的文件組的數量與分區的數量一致。 這保證了記錄鍵查找的一致性。

值得注意的是,當前的實現在初始化後修復了 RLI 分區中文件組的數量。 因此用戶應該傾向於過度配置文件組並相應地調整這些配置。

hoodie.metadata.record.index.max.filegroup.count
hoodie.metadata.record.index.min.filegroup.count
hoodie.metadata.record.index.max.filegroup.size
hoodie.metadata.record.index.growth.factor

在未來的開發迭代中,RLI 應該能夠通過動態重新平衡文件組來克服這一限制,以適應不斷增加的記錄數量。

在數據表寫入時更新 RLI

在常規寫入期間,RLI 分區將作爲事務的一部分進行更新。 元數據記錄將使用傳入的記錄鍵及其相應的位置信息生成。 鑑於 RLI 分區包含記錄鍵和位置的精確映射,對數據表的更新插入將導致將相應的鍵更新插入到 RLI 分區。所採用的哈希函數將保證相同的鍵被路由到同一文件組。

寫入索引

作爲寫入流程的一部分,RLI 遵循高級索引流程,與任何其他全局索引類似:對於給定的記錄集,如果索引發現每個記錄存在於任何現有文件組中,它就會使用位置信息標記每個記錄。 關鍵區別在於存在性測試的真實來源——RLI 分區。 下圖說明了標記流程的詳細步驟。

標記的記錄將被傳遞到 Hudi 寫入句柄,並對它們各自的文件組進行寫入操作。 索引過程是對錶應用更新的關鍵步驟,因爲其效率直接影響寫入延遲。 在後面的部分中,我們將使用基準測試結果展示記錄索引的性能。

讀取流程

記錄級別索引也集成在查詢端。 在涉及針對記錄鍵列進行相等性檢查(例如,EqualTo 或 IN)的查詢中,Hudi 的文件索引實現優化了文件裁剪過程。 這種優化是通過利用 RLI 精確定位完成查詢所需讀取的文件組來實現的。

存儲

存儲效率是設計的另一個重要方面。 每個RLI映射條目必須包含一些精確定位文件所必需的信息,例如記錄鍵、分區路徑、文件組id等。爲了優化存儲,RLI採用了一些壓縮技術,例如對文件組id進行編碼(以UUID的形式) ) 轉換爲 2 個 Long 來表示高位和低位。 使用 Gzip 壓縮和 4MB 塊大小,單個 RLI 記錄的平均大小僅爲 48 字節。 爲了更實際地說明這一點,假設我們有一個包含 100TB 數據的表,其中包含大約 10 億條記錄(平均記錄大小 = 100Kb)。 RLI 分區所需的存儲空間約爲 48 Gb,不到總數據大小的 0.05%。 由於 RLI 包含與數據表相同數量的條目,因此存儲優化對於使 RLI 實用起來至關重要,特別是對於 PB 大小及以上的表。

RLI 利用低成本存儲來實現類似於 HBase 索引的快速查找過程,同時避免運行額外服務的開銷。 在下一節中我們將回顧一些基準測試結果以展示其性能優勢。

性能

我們對記錄級別索引進行了全面的基準分析,評估寫入延遲、索引查找延遲和數據shuffle等方面,並與 Hudi 中現有的索引機制進行比較。 除了寫入操作的基準之外,我們還將展示點查的查詢延遲的減少。實驗使用Hudi 0.14.0和Spark 3.2.1。

與 Hudi 中的全局簡單索引 (GSI) 相比,記錄級別索引 (RLI) 的設計具有顯着的性能優勢,因爲大大減少了掃描空間並最大限度地減少了數據shuffle。 GSI 在數據表的所有分區中的傳入記錄和現有數據之間執行join操作,從而導致大量數據Shuffle和精確定位記錄的計算開銷。 另一方面 RLI 通過哈希函數有效地提取位置信息,通過僅從元數據表加載感興趣的文件組,從而顯着減少數據shuffle量。

寫入延遲

在第一組實驗中,我們建立了兩個管道:一個使用 GSI 配置,另一個使用 RLI 配置。 每個管道在包含 10 個 m5.4xlarge 核心實例的 EMR 集羣上執行,並設置爲將批量 200Mb 數據攝取到包含 20 億條記錄的 1TB 數據集中。 RLI 分區配置有 1000 個文件組。 對於 N 批次的攝取,使用 RLI 的平均寫入延遲比 GSI 顯着提高了 72%。

注意:在Hudi中的Global Simple Index和Global Bloom Index之間,由於記錄鍵的隨機性,前者產生了更好的結果。 因此我們在圖表中省略了GSI的呈現。

索引查找延遲

我們還使用 HoodieReadClient 隔離了索引查找步驟,以準確衡量索引效率。 通過在包含 20 億條記錄的 1TB 數據集中查找 400,000 條記錄 (0.02%) 的實驗,RLI 比 GSI 提高了 72%,與端到端寫入延遲結果一致。

數據Shuffle

在索引查找實驗中,我們觀察到 GSI 大約有 85Gb 的數據shuffle ,而RLI只有 700Mb 的數據shuffle。這反映出與 GSI 相比,使用 RLI 時數據shuffle減少了 92%。

查詢延遲

記錄級別索引將極大地提高在記錄鍵列上使用“EqualTo”和“IN”謂詞的 Spark 查詢。 我們創建了一個 400GB Hudi 表,包含 20,000 個文件組。 當我們執行基於單個記錄鍵的查詢時,我們觀察到查詢時間有了顯着的改進。 啓用 RLI 後,查詢時間從 977 秒減少到僅 12 秒,延遲減少了 98%。

何時使用

RLI 總體表現出出色的性能,將更新和刪除效率提升到一個新的水平,並在執行鍵匹配查詢時快速跟蹤讀取。 啓用 RLI 也很簡單,只需設置一些配置標誌即可。 下面我們總結了一個表格,突出顯示了 RLI 與其他常見 Hudi 索引類型相比的重要特徵。

| |
Record Level Index | Global Simple Index | Global Bloom Index | HBase Index | Bucket Index |
| --- | --- | --- | --- | --- | --- |
| Performant look-up in general | Yes | No | No | Yes, with possible throttling issues | Yes |
| Boost both writes and reads | Yes | No, write-only | No, write-only | No, write-only | No, write-only |
| Easy to enable | Yes | Yes | Yes | No, require HBase server | Yes |

許多實際應用程序將受益於 RLI 的使用。 一個常見的例子是滿足 GDPR 要求。 通常當用戶提出請求時,將提供一組 ID 來標識要刪除的記錄,這些記錄將被更新(列無效)或永久刪除。 通過啓用 RLI,執行此類更改的離線作業將變得更加高效,從而節省成本。 在讀取方面,通過某些跟蹤 ID 收集歷史事件的分析師或工程師也將體驗到來自鍵匹配查詢的極快響應。

雖然 RLI 相對於所有其他指數類型具有上述優勢,但在使用它時考慮某些方面也很重要。 與任何其他全局索引類似,RLI 要求表中所有分區的記錄鍵唯一性。 由於 RLI 跟蹤所有記錄鍵和位置,因此對於大型表來說,初始化過程可能需要一些時間。 在大型工作負載極度傾斜的場景中,由於當前設計的限制,RLI 可能無法達到所需的性能。

未來的工作

在記錄級別索引的初始版本中有某些限制。 正如“初始化”部分中提到的,文件組的數量必須在創建 RLI 分區期間預先確定。 Hudi 確實對現有表使用一些啓發式方法和增長因子,但對於新表,建議爲 RLI 設置適當的文件組配置。 隨着數據量的增加,當需要額外的文件組進行擴展時,RLI 分區需要重新引導。 爲了滿足重新平衡的需要,可以採用一致的哈希技術。

另一個有價值的增強功能涉及支持輔助列與記錄關鍵字段的索引,從而滿足更廣泛的查詢。 在讀取器方面,計劃將更多查詢引擎(例如 Presto 和 Trino)與記錄級別索引集成,以充分利用 Hudi 元數據表提供的性能優勢。

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