ApacheHudi使用問題彙總(二)

1. Hudi Cleaner是做什麼的?

       Hudi Cleaner(清理程序)通常在 commitdeltacommit之後立即運行,刪除不再需要的舊文件。如果在使用增量拉取功能,請確保配置了清理項來保留足夠數量的commit(提交),以便可以回退,另一個考慮因素是爲長時間運行的作業提供足夠的時間來完成運行。否則,Cleaner可能會刪除該作業正在讀取或可能被其讀取的文件,並使該作業失敗。通常,默認配置爲10會允許每30分鐘運行一次提取,以保留長達5(10 * 0.5)個小時的數據。如果以繁進行攝取,或者爲查詢提供更多運行時間,可增加 hoodie.cleaner.commits.retained配置項的值。

2. Hudi的模式演進(schema evolution)是什麼?

      Hudi使用 Avro作爲記錄的內部表示形式,這主要是由於其良好的架構兼容性和演進特性。這也是攝取或ETL管道保持可靠的關鍵所在。只要傳遞給Hudi的模式(無論是在 DeltaStreamer顯示提供還是由 SparkDatasourceDataset模式隱式)向後兼容(例如不刪除任何字段,僅追加新字段),Hudi將無縫處理新舊數據的的讀/寫操作並會保持Hive模式爲最新。

3. 如何壓縮(compaction)MOR數據集?

     在MOR數據集上進行壓縮的最簡單方法是運行內聯壓縮(compaction inline),但需要花費更多時間。通常情況下,當有少量的遲到數據落入舊分區時,這可能特別有用,在這種情況下,你可能想壓縮最後的N個分區,同時等待較舊的分區積累足夠的日誌。其最終會將大多數最新數據轉化查詢優化的列格式,即從日誌log文件轉化爲parquet文件。

還可異步運行壓縮,這可以通過單獨壓縮任務來完成。如果使用的是 DeltaStreamer,則可以在連續模式下運行壓縮,在該模式下,會在單個spark任務內同時進行攝取和壓縮。

4. Hudi寫入的性能/最大延遲

      寫入Hudi的速度在寫入操作以及在調整文件大小做了權衡。就像數據庫在磁盤上的直接/原始文件產生I/O開銷一樣,與讀取/寫入原始DFS文件或支持數據庫之類的功能相比,Hudi可能會產生開銷。Hudi採用了數據庫文獻中的技術,以使這些開銷最少,具體可參考下表。

與許多管理時間序列數據的系統一樣,如果鍵具有時間戳前綴或單調增加/減少,則Hudi的性能會更好,而我們幾乎總是可以實現這一目標。即便是UUID密鑰,也可以按照以下技巧來獲得有序的密鑰另請參閱調優指南以獲取有關JVM和其他配置的更多提示。

5. Hudi讀取/查詢的性能

  • 對於讀優化視圖(Read optimized views),可以達到Hive/Spark/Presto的parquet表相同的查詢性能。

  • 對於增量視圖( Incremental views),相對於全表掃描所花費的時間,速度更快。例如,如果在最後一個小時中,在1000個文件的分區中僅更改了100個文件,那麼與完全掃描該分區以查找新數據相比,使用Hudi中的增量拉取可以將速度提高10倍。

  • 對於實時視圖(Real time views),性能類似於Hive/Spark/Presto中Avro格式的表。

6. 如何避免創建大量小文件?

     Hudi的一項關鍵設計是避免創建小文件,並且始終寫入適當大小的文件,其會在攝取/寫入上花費更多時間以保持查詢的高效。寫入非常小的文件然後進行合併的方法只能解決小文件帶來的系統可伸縮性問題,其無論如何都會因爲小文件而降低查詢速度。

執行插入更新/插入操作時,Hudi可以配置文件大小。(注意:bulk_insert操作不提供此功能,其設計爲用來替代 spark.write.parquet。)

對於寫時複製,可以配置基本/parquet文件的最大大小和軟限制,小於限制的爲小文件。Hudi將在寫入時會嘗試將足夠的記錄添加到一個小文件中,以使其達到配置的最大限制。例如,對於 compactionSmallFileSize=100MBlimitFileSize=120MB,Hudi將選擇所有小於100MB的文件,並嘗試將其增加到120MB。

對於讀時合併,幾乎沒有其他配置。可以配置最大日誌大小和一個因子,該因子表示當數據從avro轉化到parquet文件時大小減小量。

HUDI-26將較小的文件組合併成較大的文件組,從而提升提升性能。

7. 如何使用DeltaStreamer或Spark DataSource API寫入未分區的Hudi數據集?

   Hudi支持寫入未分區數據集。如果要寫入未分區的Hudi數據集並執行配置單元表同步,需要在傳遞的屬性中設置以下配置:

hoodie.datasource.write.keygenerator.class=org.apache.hudi.NonpartitionedKeyGenerator

hoodie.datasource.hive_sync.partition_extractor_class=org.apache.hudi.hive.NonPartitionedExtractor

 

8. 爲什麼必須進行兩種不同的配置才能使Spark與Hudi配合使用?

  非Hive引擎傾向於自己列舉DFS上的文件來查詢數據集。例如,Spark直接從文件系統(HDFS或S3)讀取路徑。

Spark調用如下:

  • org.apache.spark.rdd.NewHadoopRDD.getPartitions

  • org.apache.parquet.hadoop.ParquetInputFormat.getSplits

  • org.apache.hadoop.mapreduce.lib.input.FileInputFormat.getSplits

在不瞭解Hudi的文件佈局的情況下,引擎只會簡單地讀取所有parquet文件並顯示結果,這樣結果中可能會出現大量的重複項。

有兩種方法可以配置查詢引擎來正確讀取Hudi數據集:

A) 調用 HoodieParquetInputFormat#getSplitsHoodieParquetInputFormat#getRecordReader方法

  • Hive原生就會執行此操作,因爲InputFormat是Hive中插入表格式的抽象。HoodieParquetInputFormat擴展了MapredParquetInputFormat,其是hive的一種輸入格式,將Hudi表註冊到Hive metastore中。

  • 當使用 UseFileSplitsFromInputFormat註解時,Presto會使用輸入格式來獲取分片,然後繼續使用自己的優化/矢量化parquet讀取器來查詢寫時複製表。

  • 可以使用 --conf spark.sql.hive.convertMetastoreParquet=false將Spark強制回退到 HoodieParquetInputFormat類。

B) 使引擎調用路徑過濾器(path filter)或其他方式來直接調用Hudi類來過濾DFS上的文件並挑選最新的文件切片

  • 即使我們可以強制Spark回退到使用InputFormat類,但這樣做可能會失去使用Spark的parquet讀取器的能力。

  • 爲保持parquet文件讀取性能的優勢,我們將 HoodieROTablePathFilter設置爲路徑過濾器,並在Spark 的Hadoop Configuration中指定,確保始終選擇Hudi相關文件的文件夾(路徑)或文件的最新文件片。這將過濾出重複的條目並顯示每個記錄的最新條目。

9. 已有數據集,如何使用部分數據來評估Hudi

可以將該數據的一部分批量導入到新的hudi表中。例如一個月的數據

spark.read.parquet("your_data_set/path/to/month")

.write.format("org.apache.hudi")

.option("hoodie.datasource.write.operation", "bulk_insert")

.option("hoodie.datasource.write.storage.type", "storage_type") // COPY_ON_WRITE or MERGE_ON_READ

.option(RECORDKEY_FIELD_OPT_KEY, "<your key>").

.option(PARTITIONPATH_FIELD_OPT_KEY, "<your_partition>")

...

.mode(SaveMode.Append)

.save(basePath);

 

一旦有初始副本後,就可選擇一些數據樣本進行更新插入操作

spark.read.parquet("your_data_set/path/to/month").limit(n) // Limit n records

.write.format("org.apache.hudi")

.option("hoodie.datasource.write.operation", "upsert")

.option(RECORDKEY_FIELD_OPT_KEY, "<your key>").

.option(PARTITIONPATH_FIELD_OPT_KEY, "<your_partition>")

...

.mode(SaveMode.Append)

.save(basePath);

對於讀取的表的合併,若還需要調度和運行壓縮(compaction)任務。則可以使用 spark sumbit直接提交 org.apache.hudi.utilities.HoodieCompactor運行壓縮,也可以使用HUDI CLI運行壓縮。

發佈了65 篇原創文章 · 獲贊 8 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章