【Hadoop】Hudi 基礎知識詳解
1. Hudi 簡(jiǎn)介
Apache Hudi將核心倉庫和數據庫功能直接帶到數據湖中。Hudi提供了表、事務(wù)、高效upserts/刪除、高級索引、流式攝取服務(wù)、數據群集/壓縮優(yōu)化以及并發(fā),同時(shí)保持數據以開(kāi)源文件格式保留。
Hudi是Hadoop Upserts and Incrementals
縮寫(xiě),用于管理分布式文件系統DFS上大型分析數據集存儲。
Hudi是一種針對分析型業(yè)務(wù)的、掃描優(yōu)化的數據存儲抽象,它能夠使DFS數據集在分鐘級的時(shí)延內支持變更,也支持下游系統對這個(gè)數據集的增量處理。
1.1 Hudi特性和功能
- 支持快速Upsert以及可插拔的索引。
- 支持原子方式操作,且支持回滾。
- 寫(xiě)入和插件操作之間的快照隔離。
- savepoint用戶(hù)數據恢復的保存點(diǎn)。
- 使用統計信息管理文件大小和布局。
- 行和列的異步壓縮。
- 具有時(shí)間線(xiàn)來(lái)追蹤元數據血統。
- 通過(guò)聚類(lèi)優(yōu)化數據集。
1.2 Hudi 基礎架構
- 支持通過(guò)Flink、Spark、Hive等工具,將數據寫(xiě)入到數據庫存儲。
- 支持 HDFS、S3、Azure、云等等作為數據湖的數據存儲。
- 支持不同查詢(xún)引擎,如:Spark、Flink、Presto、Hive、Impala、Aliyun DLA。
- 支持 spark、flink、map-reduce 等計算引擎對 hudi 的數據進(jìn)行讀寫(xiě)操作。
1.3 Hudi 功能
- Hudi是在大數據存儲上的一個(gè)數據集,可以將Change Logs 通過(guò)upsert方式合并到Hudi。
- Hudi對上可以暴露成一個(gè)普通的Hive或者Spark表,通過(guò)API或者命令行的方式可以獲取到增量修改信息,繼續供下游消費。
- Hudi保管修改歷史,可以做到時(shí)間旅行以及回退。
- Hudi內部有主鍵到文件級別的索引,默認記錄文件的是布隆過(guò)濾器。
1.4 Hudi的特性
Apache Hudi支持在Hadoop兼容的存儲之上存儲大量數據,不僅可以批處理,還可以在數據湖上進(jìn)行流處理。
- Update/Delete 記錄:Hudi 使用細粒度的文件/記錄級別索引來(lái)支持 Update/Delete
記錄,同時(shí)還提供寫(xiě)操作的事務(wù)保證。查詢(xún)會(huì )處理后一個(gè)提交的快照,并基于此輸出結果。 - 變更流:Hudi 對獲取數據變更提供了的支持,可以從給定的 時(shí)間點(diǎn) 獲取給定表中已 updated / inserted / deleted 的所有記錄的增量流,并解鎖新的查詢(xún)姿勢(類(lèi)別)。
- Apache Hudi 本身不存儲數據,僅僅管理數據。
- Apache Hudi 也不分析數據,需要使用計算分析引擎,查詢(xún)和保存數據,比如 Spark 或 Flink;
- 使用 Hudi 時(shí),加載 jar 包,底層調用 API,所以需要依據使用大數據框架版本,編譯 Hudi 源碼,獲取對應依賴(lài)jar包。
2.核心概念
2.1 Timeline
在Hudi中維護一個(gè)所有操作的時(shí)間軸,每個(gè)操作對應時(shí)間上面的instant,每個(gè)instant提供表的view,同時(shí)支持按照時(shí)間順序搜索數據。
Instant action
: 對表的具體操作。Instant time
: 當前操作執行的時(shí)間戳。state
:當前instant的狀態(tài)。
Hudi 能夠保證所有的操作都是原子性的,按照時(shí)間軸的。Hudi的關(guān)鍵操作包含:
COMMITS
:一次原子性寫(xiě)入數據到Hudi的操作。CLEANS
:刪除表中不再需要的舊版本文件的后臺活動(dòng)。DELTA_COMMIT
:delta commit
主要是一批原子性寫(xiě)入MOR表,其中部分或者全部都會(huì )寫(xiě)入delta logs。COMPACTION
: 在后臺將不同操作類(lèi)型進(jìn)行壓縮,將log文件壓縮為列式存儲格式。ROLLBACK
: 將不成功的commit/delta commit
進(jìn)行回滾。SAVEPOINT
: 將某些文件標記為已保存,方便異常場(chǎng)景下恢復。
State詳細解釋?zhuān)?/p>
REQUESTED
: 表示已計劃但尚未啟動(dòng)操作INFLIGHT
: 表示當前正在執行操作COMPLETED
: 表示在時(shí)間線(xiàn)上完成一項操作
2.2 文件布局
- Hudi在分布式文件系統的基本路徑下將數據表組織成目錄結構。
- 一個(gè)表包含多個(gè)分區。
- 在每個(gè)分區里面,文件被分為文件組,由文件id作為唯一標識。
- 每個(gè)文件組當中包含多個(gè)文件切片。
- 每個(gè)切片都包含一個(gè)在特定提交/壓縮instant操作生成的基本文件(.parquet);日志文件(.log)這些文件包含自生成基本
文件以來(lái)對基本文件的插入/更新。
Hudi采用多版本并發(fā)控制(MVCC),其中壓縮操作合并日志和基本文件以生成新的文件切片,而清理操作清除未使用/舊的
文件切片以回收文件系統上的空間。
2.3 表&查詢(xún)類(lèi)型
表類(lèi)型 | 支持查詢(xún)類(lèi)型 |
---|---|
Copy On Write | 快照查詢(xún) + 增量查詢(xún) |
Merge On Read | 快照查詢(xún) + 增量查詢(xún) + 讀取優(yōu)化查詢(xún) |
2.3.1 表類(lèi)型
2.3.1.1 Copy On Write
使用排他列式文件格式(比如:parquet)存儲,簡(jiǎn)單地更新版本&通過(guò)在寫(xiě)入期間執行同步合并來(lái)重寫(xiě)文件。
下面從概念上說(shuō)明了這是如何工作的,當數據寫(xiě)入寫(xiě)時(shí)復制表和在其上運行的兩個(gè)查詢(xún)時(shí)。
在寫(xiě)入數據時(shí),對現有文件組的更新會(huì )為該文件組生成一個(gè)帶有提交即時(shí)時(shí)間戳的新切片,而插入會(huì )分配一個(gè)新文件組并為該文件組寫(xiě)入其第一個(gè)切片。上面紅色標出來(lái)的就是新提交的。
2.3.1.1 Merge On Read
使用列式(比如:parquet) + 基于行的文件格式 (比如:avro) 組合存儲數據。更新記錄到增量文件中,然后壓縮以同步或
異步生成新版本的柱狀文件。
將每個(gè)文件組的傳入追加存儲到基于行的增量日志中,以通過(guò)在查詢(xún)期間將增量日志動(dòng)態(tài)應用到每個(gè)文件id的最新版本來(lái)支持快照查詢(xún)。
因此,這種表類(lèi)型試圖均衡讀取和寫(xiě)入放大,以提供接近實(shí)時(shí)的數據。
對比維度 | CopyOnWrite | MergeOnRead |
---|---|---|
數據延遲 | Higher | Lower |
查詢(xún)延遲 | Lower | Higher |
更新成本(I/O) | Higher(需要重寫(xiě)parquet) | Lower(添加到delta log) |
Parquet文件大小 | Smaller(高更新(I/O)成本) | Larger(低更新成本) |
寫(xiě)入放大 | Higher | Lower(取決于壓縮策略) |
2.3.2 查詢(xún)類(lèi)型
- 快照查詢(xún):在此視圖上的查詢(xún)可以查看給定提交或壓縮操作時(shí)表的最新快照。
- 對于讀時(shí)合并表(MOR表) 該視圖通過(guò)動(dòng)態(tài)合并最新文件切片的基本文件(例如parquet)和增量文件(例如avro)來(lái)提供近實(shí)時(shí)數據集(幾分鐘的延遲)。
- 對于寫(xiě)時(shí)復制表(COW表),它提供了現有parquet表的插入式替換,同時(shí)提供了插入/刪除和其他寫(xiě)側功能。
- 增量查詢(xún):對該視圖的查詢(xún)只能看到從某個(gè)提交/壓縮后寫(xiě)入數據集的新數據。提供了流式變化記錄,用來(lái)支持增量讀取
- 讀優(yōu)化查詢(xún):
3. Hudi索引
Hudi 通過(guò)索引機制將給定的 hoodie key(record key + 分區路徑)映射到文件id,從而提供高效的更新插入。
一旦record的第一個(gè)版本寫(xiě)入文件,record 的key和文件ID 之間的映射就不會(huì )改變。
對于COW表來(lái)講:
可以避免掃描整個(gè)文件系統,達到支持快速u(mài)psert/delete操作。
對于MOR表來(lái)講:
允許限制base文件中需要合并的records的數量。對于一個(gè)base文件只需要根據當前base文件的record的跟新等進(jìn)行合并。
Comparion cost對比:
Hudi支持的索引如下:
名稱(chēng) | 備注 |
---|---|
Bloom索引 | 采用根據記錄key構建的布隆過(guò)濾器,還可以選擇使用記錄key范圍修剪候選文件。 |
GLOBAL_BLOOM索引 | 與Boolm索引類(lèi)似,但是作用范圍是全局 |
Simple索引 | 針對從存儲上的表中提取的鍵對傳入的更新/刪除記錄執行精益聯(lián)接。 |
GLOBAL_SIMPLE索引 | 與Simple類(lèi)似,但是作用范圍是全局 |
HBase索引 | 將index信息保存到Hbase當中。 |
INMEMORY索引 | 在Spark、Java程序、Flink的內存中保存索引信息,Flink和Java默認使用當前索引 |
BUCKET索引 | 使用桶hash的方式定位文件組,在大數據量情況下效果較好??梢酝ㄟ^(guò)hoodie.index.bucket.engine 指定bucket引擎。 |
RECORD_INDEX索引 | 索引將record的key保存到 Hudi元數據表中的位置映射。 |
自定義索引 | 自定義實(shí)現的索引。 |
BUCKET索:
- SIMPLE(default): 每個(gè)分區的文件組使用固定數量的存儲桶,無(wú)法縮小或擴展。同時(shí)支持COW和MOR表。由于存儲桶的數量無(wú)法更改且存儲桶和文件組之間采用一對一映射,因此該索引不太適合數據傾斜的情況。
- CONSISTENT_HASHING: 支持動(dòng)態(tài)數量的存儲桶,可以根據存儲桶的大小調整桶的數量。
4. Hudi 數據管理
4.1 Hudi 表數據結構
Hudi 表的數據文件一般使用 HDFS 進(jìn)行存儲。從文件路徑和類(lèi)型來(lái)講,Hudi表的存儲文件分為兩類(lèi)。
- .hoodie 文件,
- amricas 和 asia 相關(guān)的路徑是 實(shí)際的數據文件,按分區存儲,分區的路徑 key 是可以指定的。
4.1.1 .hoodie文件
