大數(shù)據(jù)Hadoop之——新一代流式數(shù)據(jù)湖平臺 Apache Hudi
一、概述
Hudi(Hadoop Upserts Deletes and Incrementals),簡稱Hudi,是一個流式數(shù)據(jù)湖平臺,支持對海量數(shù)據(jù)快速更新,內(nèi)置表格式,支持事務(wù)的存儲層、 一系列表服務(wù)、數(shù)據(jù)服務(wù)(開箱即用的攝取工具)以及完善的運(yùn)維監(jiān)控工具,它可以以極低的延遲將數(shù)據(jù)快速存儲到HDFS或云存儲(S3)的工具,最主要的特點(diǎn)支持記錄級別的插入更新(Upsert)和刪除,同時還支持增量查詢。
- Apache Hudl本身不存儲數(shù)據(jù),僅僅管理數(shù)據(jù),借助外部存儲引擎存儲數(shù)據(jù),比如HDFS;
 - 此外,Apache Hudi也不分析數(shù)據(jù),需要使用計(jì)算分析引擎,查詢和保存數(shù)據(jù),比如Spark或Flink;
 - 使用Hudi時,加載jar包,底層調(diào)用API,所以需要依據(jù)使用大數(shù)據(jù)框架版本,編譯Hudi源碼,獲取對應(yīng)依賴jar包。
 
GitHub地址:https://github.com/apache/hudi
官方文檔:https://hudi.apache.org/cn/docs/overview

上圖從下到上,由左向右看
- hudi 底層的數(shù)據(jù)可以存儲到hdfs、s3、azure、alluxio等存儲。
 - hudi 可以使用spark/flink 計(jì)算引擎來消費(fèi) kafka、pulsar 等消息隊(duì)列的數(shù)據(jù),而這些數(shù)據(jù)可能來源于 app 或者微服務(wù)的業(yè)務(wù)數(shù)據(jù)、日志數(shù)據(jù),也可以是 mysql 等數(shù)據(jù)庫的 binlog 日志數(shù)據(jù)。
 - spark/hudi 首先將這些數(shù)據(jù)處理為 hudi 格式的 row tables (原始表),然后這張?jiān)急砜梢员?Incremental ETL (增量處理)生成一張 hudi 格式的 derived tables 派生表。
 - hudi 支持的查詢引擎有:trino、hive、impala、spark、presto 等。
 - 支持 spark、flink、map-reduce 等計(jì)算引擎繼續(xù)對 hudi 的數(shù)據(jù)進(jìn)行再次加工處理。
 
二、Hudi 架構(gòu)
- 通過DeltaStreammer、Flink、Spark等工具,將數(shù)據(jù)攝取到數(shù)據(jù)湖存儲,可使用HDFS作為數(shù)據(jù)湖的數(shù)據(jù)存儲;
 - 基于HDFS可以構(gòu)建Hudi的數(shù)據(jù)湖;
 - Hudi提供統(tǒng)一的訪問Spark數(shù)據(jù)源和Flink數(shù)據(jù)源;
 - 外部通過不同引擎,如:Spark、Flink、Presto、Hive、Impala、Aliyun DLA、AWS Redshit訪問接口;
 

三、Hudi的表格式
Hudi提供兩類型表:寫時復(fù)制(Copy on Write,COW)表和讀時合并(Merge On Read,MOR)表。
- 對于 Copy-On-Write Table,用戶的 update 會重寫數(shù)據(jù)所在的文件,所以是一個寫放大很高,但是讀放大為 0,適合寫少讀多的場景。
 - 對于 Merge-On-Read Table,整體的結(jié)構(gòu)有點(diǎn)像 LSM-Tree,用戶的寫入先寫入到 delta data 中,這部分?jǐn)?shù)據(jù)使用行存,這部分 delta data 可以手動 merge 到存量文件中,整理為 parquet 的列存結(jié)構(gòu)。
 
1)Copy on Write(寫時復(fù)制)
簡稱COW,顧名思義,它是在數(shù)據(jù)寫入的時候,復(fù)制一份原來的拷貝,在其基礎(chǔ)上添加新數(shù)據(jù)。正在讀數(shù)據(jù)的請求,讀取的是最近的完整副本,這類似Mysql 的MVCC的思想。

優(yōu)點(diǎn):讀取時,只讀取對應(yīng)分區(qū)的一個數(shù)據(jù)文件即可,較為高效;
缺點(diǎn):數(shù)據(jù)寫入的時候,需要復(fù)制一個先前的副本再在其基礎(chǔ)上生成新的數(shù)據(jù)文件,這個過程比較耗時。
2)Merge On Read(讀時合并)
簡稱MOR,新插入的數(shù)據(jù)存儲在delta log 中,定期再將delta log合并進(jìn)行parquet數(shù)據(jù)文件。讀取數(shù)據(jù)時,會將delta log跟老的數(shù)據(jù)文件做merge,得到完整的數(shù)據(jù)返回。下圖演示了MOR的兩種數(shù)據(jù)讀寫方式。

優(yōu)點(diǎn):由于寫入數(shù)據(jù)先寫delta log,且delta log較小,所以寫入成本較低;
缺點(diǎn):需要定期合并整理compact,否則碎片文件較多。讀取性能較差,因?yàn)樾枰獙elta log和老數(shù)據(jù)文件合并
3)COW vs MOR
COW表,用戶在 snapshot 讀取的時候會掃描所有最新的 FileSlice 下的 base file。
MOR表,在 READ OPTIMIZED 模式下,只會讀最近的經(jīng)過 compaction 的 commit。
權(quán)衡  | 寫時復(fù)制(COW )  | 讀時合并(MOR )  | 
數(shù)據(jù)延遲  | 更高  | 更低  | 
更新代價(jià)( I/O)  | 更高(重寫整個parquet文件)  | 更低(追加到增量日志)  | 
Parque&件大小  | 更?。ǜ吒麓鷥r(jià)( I/O)  | 更大(低更新代價(jià))  | 
寫放大  | 更高  | 更低(取決于壓縮策略)  | 
適用場景  | 寫少讀多  | 寫多讀少  | 
四、元數(shù)據(jù)表(Metadata Table)
Apache Hudi元數(shù)據(jù)表可以顯著提高查詢的讀/寫性能。元數(shù)據(jù)表的主要目的是消除“列出文件”操作的要求。
讀取和寫入數(shù)據(jù)時,將執(zhí)行文件列表操作以獲取文件系統(tǒng)的當(dāng)前視圖。當(dāng)數(shù)據(jù)集很大時,列出所有文件可能是性能瓶頸,但更重要的是,對于AWS S3等云存儲系統(tǒng),由于某些請求限制,大量的文件列出請求有時會導(dǎo)致節(jié)流。相反,元數(shù)據(jù)表將主動維護(hù)文件列表,并消除遞歸文件列表操作的需要。
五、索引(Indexing)
Hudi通過索引機(jī)制將給定的hoodie鍵(記錄鍵+分區(qū)路徑)一致地映射到文件id,從而提供高效的升級。一旦將記錄的第一個版本寫入文件,記錄鍵和文件組/文件id之間的映射就不會改變。簡而言之,映射的文件組包含一組記錄的所有版本。

目前,Hudi支持以下索引類型:
Bloom索引(默認(rèn)):使用由記錄鍵構(gòu)建的Bloom過濾器,也可以使用記錄鍵范圍修剪候選文件。
簡單索引:根據(jù)從存儲上的表中提取的鍵,對傳入的更新/刪除記錄執(zhí)行精簡聯(lián)接。
HBase索引:管理外部Apache HBase表中的索引映射。
自定義索引:當(dāng)然也可以擴(kuò)展這個公共API來實(shí)現(xiàn)自定義索引。
六、查詢類型(Query Type)
Hudi支持三種不同的查詢表的方式:Snapshot Queries(快照查詢)、Incremental Queries(增量查詢)和Read Optimized Queries(讀優(yōu)化查詢)。
1)Snapshot Queries(快照查詢)
查詢查看給定提交或壓縮操作時表的最新快照。在合并讀取表的情況下,它通過動態(tài)合并最新文件切片的基本文件和增量文件來公開接近實(shí)時的數(shù)據(jù)(幾分鐘)。
對于隨寫復(fù)制表,它提供了現(xiàn)有拼花桌的插入式替換,同時提供了upsert/delete和其他寫入端功能。
2)Incremental Queries(增量查詢)
在給定的提交/壓縮之后,查詢只會看到寫入表的新數(shù)據(jù)。這有效地提供了更改流以啟用增量數(shù)據(jù)管道。
可查看自給定commit/delta commit即時操作依賴新寫入的數(shù)據(jù),有效地提供變更流來啟用增量數(shù)據(jù)管道。
3)Read Optimized Queries(讀優(yōu)化查詢)
查詢查看給定提交/壓縮操作時表的最新快照。僅顯示最新文件切片中的基/列文件,并確保與非hudi列表相比具有相同的列查詢性能。
讀優(yōu)化查詢和快照查詢相同僅訪問基本文件,提供給定文件片自上次執(zhí)行壓縮操作以來的數(shù)據(jù)。通常查詢數(shù)據(jù)的最新程度的保證取決于壓縮策略。
七、計(jì)算模型
在hudi過去的使用場景里,和大部分公司的架構(gòu)類似,采用批式和流式共存的Lambda架構(gòu),后來Uber提出增量Incremental模型,相對批式來講,更加實(shí)時,相對流式而言,更加經(jīng)濟(jì)。
1)批式模型(Batch)
批式模型就是使用MapReduce、Hive、Spark等典型的批計(jì)算引擎,以小時任務(wù)或者天任務(wù)的形式來做數(shù)據(jù)計(jì)算。特性如下:
延遲:小時級延遲或者天級別延遲。這里的延遲不單單指的是定時任務(wù)的時間,在數(shù)據(jù)架構(gòu)里,這里的延遲時間通常是定時任務(wù)間隔時間+一系列依賴任務(wù)的計(jì)算時間+數(shù)據(jù)平臺最終可以展示結(jié)果的時間。數(shù)據(jù)量大、邏輯復(fù)雜的情況下,小時任務(wù)計(jì)算的數(shù)據(jù)通常真正延遲的時間是2-3小時。
數(shù)據(jù)完整度:數(shù)據(jù)較完整。以處理時間為例,小時級別的任務(wù),通常計(jì)算的原始數(shù)據(jù)已經(jīng)包含了小時內(nèi)的所有數(shù)據(jù),所以得到的數(shù)據(jù)相對較完整。但如果業(yè)務(wù)需求是事件時間,這里涉及到終端的一些延遲上報(bào)機(jī)制,在這里,批式計(jì)算任務(wù)就很難派上用場。
成本:成本很低。只有在做任務(wù)計(jì)算時,才會占用資源,如果不做任務(wù)計(jì)算,可以將這部分批式計(jì)算資源出讓給在線業(yè)務(wù)使用。從另一個角度來說成本是挺高的,如原始數(shù)據(jù)做了一些增刪改查,數(shù)據(jù)晚到的情況,那么批式任務(wù)是要全量重新計(jì)算。
2)流式模型(Stream)
流式模型,典型的就是使用Flink來進(jìn)行實(shí)時的數(shù)據(jù)計(jì)算,特性:
延遲:很短,甚至是實(shí)時。
數(shù)據(jù)完整度:較差。因?yàn)榱魇揭娌粫鹊剿袛?shù)據(jù)到齊之后再開始計(jì)算,所以有一個watermark的概念,當(dāng)數(shù)據(jù)的時間小于watermark時,就會被丟棄,這樣是無法對數(shù)據(jù)完整度有一個絕對的保障。在互聯(lián)網(wǎng)場景中,流式模型主要用于活動時的數(shù)據(jù)大盤展示,對數(shù)據(jù)的完整度要求并不算很高。在大部分場景中,用戶需要開發(fā)兩個程序,一是流式數(shù)據(jù)生產(chǎn)流式結(jié)果,而是批式計(jì)算人物,用于次日修復(fù)實(shí)時結(jié)果。
成本:很高。因?yàn)榱魇饺蝿?wù)時常駐的,并且對于多流join的場景,通常要借助內(nèi)存或者數(shù)據(jù)庫來做state的存儲,不管是序列化開銷,還是和外部組件交互產(chǎn)生的額外IO,在大數(shù)據(jù)量下都是不容忽視的。
3)增量模型(Incremental)
針對批式和流式的優(yōu)缺點(diǎn),Uber提出了增量模型(Incremental Mode),相對批式來講,更加實(shí)時;相對流式而言,更加經(jīng)濟(jì)。 增量模型,簡單來講,就是一mini batch的形式來跑準(zhǔn)實(shí)時任務(wù)。hudi在增量模型中支持了兩個最重要的特性:
Upsert:這個主要是解決批式模型中,數(shù)據(jù)不能插入、更新的問題,有了這個特性,可以往Hive中寫入增量數(shù)據(jù),而不是每次進(jìn)行完全的覆蓋。(hudi自身維護(hù)了key-file的映射,所以當(dāng)upsert時很容易找到key對應(yīng)的文件)
Incremental Query:增量查詢,減少計(jì)算的原始數(shù)據(jù)量。以uber中司機(jī)和乘客的數(shù)據(jù)流join為例,每次抓取兩條數(shù)據(jù)流中的增量數(shù)據(jù)進(jìn)行批式的join即可,相比流式數(shù)據(jù)而言,成本要降低幾個數(shù)量級。
八、數(shù)據(jù)倉庫 VS 數(shù)據(jù)湖
1)數(shù)據(jù)類型
結(jié)構(gòu)化數(shù)據(jù)——來自關(guān)系型數(shù)據(jù)庫中的行和列。
半結(jié)構(gòu)化數(shù)據(jù)——如CSV、日志、XML、JSON等。
非結(jié)構(gòu)化數(shù)據(jù)——如email、文檔、PDF等。
二進(jìn)制數(shù)據(jù)——如圖像、音頻、視頻等。
2)數(shù)據(jù)倉庫與數(shù)據(jù)湖的區(qū)別
數(shù)據(jù)倉庫可以理解為是一個優(yōu)化的數(shù)據(jù)庫,用戶分析來自事物系統(tǒng)和業(yè)務(wù)線應(yīng)用程序的關(guān)系型數(shù)據(jù)(結(jié)構(gòu)化數(shù)據(jù)和半結(jié)構(gòu)化數(shù)據(jù))。
數(shù)據(jù)湖可以理解存儲來自業(yè)務(wù)應(yīng)用程序的關(guān)系型數(shù)據(jù)(結(jié)構(gòu)化數(shù)據(jù)),以及來自移動應(yīng)用程序、IOT設(shè)備和社交媒體的非關(guān)系型數(shù)據(jù)(非結(jié)構(gòu)化數(shù)據(jù))等所有類型數(shù)據(jù)。

特性  | 數(shù)據(jù)倉庫  | 數(shù)據(jù)湖  | 
數(shù)據(jù)  | 來自事務(wù)系統(tǒng)、運(yùn)營數(shù)據(jù)庫和業(yè)務(wù)線應(yīng)用程序的關(guān)系型數(shù)據(jù)  | 來自loT設(shè)備、網(wǎng)站、移動應(yīng)用程序、社交媒體和企業(yè)應(yīng)用程序的非關(guān)系型和關(guān)系型數(shù)據(jù)  | 
Schema  | 設(shè)計(jì)在超倉庫實(shí)施之前(寫入型Schema)  | 寫入在分析時(讀取型Schema)  | 
性價(jià)比  | 更快的查詢結(jié)果會帶來更高的存儲成本  | 更快查詢結(jié)果只需較低存儲成本  | 
數(shù)據(jù)質(zhì)量  | 可作為重要事實(shí)依據(jù)的高度監(jiān)管數(shù)據(jù)  | 任何可以或無法進(jìn)行監(jiān)管的數(shù)據(jù)(例如原始數(shù)據(jù)  | 
用戶  | 業(yè)務(wù)分析師  | 數(shù)據(jù)科學(xué)家、數(shù)據(jù)開發(fā)人員和業(yè)務(wù)分析師(使用監(jiān)管數(shù)據(jù))  | 
分析  | 批處理報(bào)告、BI和可視化  | 機(jī)器學(xué)習(xí)、詢分析、數(shù)據(jù)發(fā)現(xiàn)和分析  | 
3)湖倉一體化

Data Lakehouse (湖倉一體)是新出現(xiàn)的一種數(shù)據(jù)架構(gòu),它同時吸收了數(shù)據(jù)倉庫和數(shù)據(jù)湖的優(yōu)勢,數(shù)據(jù)分析師和數(shù)據(jù)科學(xué)家可以在同一個數(shù)據(jù)存儲中對數(shù)據(jù)進(jìn)行操作,同時它也能為公司進(jìn)行數(shù)據(jù)治理帶來更多的便利性。
LakeHouse使用新的系統(tǒng)設(shè)計(jì):直接在用于數(shù)據(jù)湖的低成本存儲上實(shí)現(xiàn)與數(shù)據(jù)倉庫中類似的數(shù)據(jù)結(jié)構(gòu)和數(shù)據(jù)管理功能。
九、源碼編譯

編譯好的Hudi 包下載地址:
鏈接:https://pan.baidu.com/s/15qKm1kW1RRtbyFT53RoeGA?pwd=ihhb
提取碼:ihhb















 
 
 









 
 
 
 