知乎上看到的這個文章,視野開闊欧募,轉(zhuǎn)載一下糜工。
URL:
https://zhuanlan.zhihu.com/p/149706105?utm_source=com.ucmobile
自己關(guān)于 Apache Hudi 的一些簡單的了解和想法颂斜。
背景
Hudi 是 Uber 主導(dǎo)開發(fā)的開源數(shù)據(jù)湖框架为迈。所以大部分的出發(fā)點都來源于 Uber 自身場景,比如司機數(shù)據(jù)和乘客數(shù)據(jù)通過訂單 Id 來做 Join 等箩兽。在 Hudi 過去的使用場景里津肛,和大部分公司的架構(gòu)類似,采用批式和流式共存的 Lambda 架構(gòu)汗贫,我們先從 延遲身坐,數(shù)據(jù)完整度還有成本 三個方面來對比一下批式和流式計算模型的區(qū)別秸脱。
批式模型
批式模型就是使用 MapReduce、Hive部蛇、Spark 等典型的批計算引擎摊唇,以小時任務(wù)或者天任務(wù)的形式來做數(shù)據(jù)計算。
- 延遲:小時級延遲或者天級別延遲涯鲁。這里的延遲不單單指的是定時任務(wù)的時間遏片,在數(shù)據(jù)架構(gòu)里,這里的延遲時間通常是定時任務(wù)間隔時間 + 一系列依賴任務(wù)的計算時間 + 數(shù)據(jù)平臺最終可以展示結(jié)果的時間撮竿。數(shù)據(jù)量大、邏輯復(fù)雜的情況下笔呀,小時任務(wù)計算的數(shù)據(jù)通常真正延遲的時間是 2-3 小時幢踏。
- 數(shù)據(jù)完整度:數(shù)據(jù)較完整。以處理時間為例许师,小時級別的任務(wù)房蝉,通常計算的原始數(shù)據(jù)已經(jīng)包含了小時內(nèi)的所有數(shù)據(jù),所以得到的數(shù)據(jù)相對較完整微渠。但如果業(yè)務(wù)需求是事件時間搭幻,這里涉及到終端的一些延遲上報機制,在這里逞盆,批式計算任務(wù)就很難派上用場檀蹋。
- 成本:成本很低。只有在做任務(wù)計算時云芦,才會占用資源俯逾,如果不做任務(wù)計算,可以將這部分批式計算資源出讓給在線業(yè)務(wù)使用舅逸。但從另一個角度來說成本是挺高的桌肴,比如原始數(shù)據(jù)做了一些增刪改查,數(shù)據(jù)晚到的情況琉历,那么批式任務(wù)是要全量重新計算坠七。
流式模型
流式模型,典型的就是使用 Flink 來進行實時的數(shù)據(jù)計算旗笔。
- 延遲:很短彪置,甚至是實時。
- 數(shù)據(jù)完整度:較差蝇恶。因為流式引擎不會等到所有數(shù)據(jù)到齊之后再開始計算悉稠,所以有一個 watermark 的概念,當數(shù)據(jù)的時間小于 watermark 時艘包,就會被丟棄的猛,這樣是無法對數(shù)據(jù)完整度有一個絕對的報障耀盗。在互聯(lián)網(wǎng)場景中,流式模型主要用于活動時的數(shù)據(jù)大盤展示卦尊,對數(shù)據(jù)的完整度要求并不算很高叛拷。在大部分場景中,用戶需要開發(fā)兩個程序岂却,一是流式數(shù)據(jù)生產(chǎn)流式結(jié)果忿薇,二是批式計算任務(wù),用于次日修復(fù)實時結(jié)果躏哩。
- 成本:很高署浩。因為流式任務(wù)是常駐的,并且對于多流 Join 的場景扫尺,通常要借助內(nèi)存或者數(shù)據(jù)庫來做 state 的存儲筋栋,不管是序列化開銷,還是和外部組件交互產(chǎn)生的額外 IO正驻,在大數(shù)據(jù)量下都是不容忽視的弊攘。
增量模型
針對批式和流式的優(yōu)缺點,Uber 提出了增量模型姑曙,相對批式來講襟交,更加實時,相對流式而言伤靠,更加經(jīng)濟捣域。
增量模型,簡單來講宴合,是以 mini batch 的形式來跑準實時任務(wù)竟宋。Hudi 在增量模型中支持了兩個最重要的特性,
- Upsert:這個主要是解決批式模型中形纺,數(shù)據(jù)不能插入丘侠、更新的問題,有了這個特性逐样,我們可以往 Hive 中寫入增量數(shù)據(jù)蜗字,而不是每次進行完全的覆蓋。(Hudi 自身維護了 key->file 的映射脂新,所以當 upsert 時很容易找到 key 對應(yīng)的文件)
- Incremental Query:增量查詢挪捕,減少計算的原始數(shù)據(jù)量。以 Uber 中司機和乘客的數(shù)據(jù)流 Join 為例争便,每次抓取兩條數(shù)據(jù)流中的增量數(shù)據(jù)進行批式的 Join 即可级零,相比流式數(shù)據(jù)而言,成本要降低幾個數(shù)量級。
在增量模型中奏纪,Hudi 提供了兩種 Table鉴嗤,分別為 Copy-On-Write 和 Merge-On-Read 兩種。
Copy-On-Write Table
對于 Copy-On-Write Table序调,用戶的 update 會重寫數(shù)據(jù)所在的文件醉锅,所以是一個寫放大很高,但是讀放大為 0发绢,適合寫少讀多的場景硬耍。對于這種 Table,提供了兩種查詢:
- Snapshot Query: 查詢最近一次 snapshot 的數(shù)據(jù)边酒,也就是最新的數(shù)據(jù)经柴。
- Incrementabl Query:用戶需要指定一個 commit time,然后 Hudi 會掃描文件中的記錄墩朦,過濾出 commit_time > 用戶指定的 commit time 的記錄坯认。
具體的流程見下圖 gif:
[圖片上傳失敗...(image-defbd0-1649294241693)]
Merge-On-Read Table
對于 Merge-On-Read Table,整體的結(jié)構(gòu)有點像 LSM-Tree介杆,用戶的寫入先寫入到 delta data 中,這部分數(shù)據(jù)使用行存韭寸,這部分 delta data 可以手動 merge 到存量文件中春哨,整理為 parquet 的列存結(jié)構(gòu)。對于這類 Tabel恩伺,提供了三種查詢:
- Snapshot Query: 查詢最近一次 snapshot 的數(shù)據(jù)赴背,也就是最新的數(shù)據(jù)。這里是一個行列數(shù)據(jù)混合的查詢晶渠。
- Incrementabl Query:用戶需要指定一個 commit time凰荚,然后 Hudi 會掃描文件中的記錄,過濾出 commit_time > 用戶指定的 commit time 的記錄褒脯。這里是一個行列數(shù)據(jù)混合的查詢便瑟。
- Read Optimized Query: 只查存量數(shù)據(jù),不查增量數(shù)據(jù)番川,因為使用的都是列式文件格式到涂,所以效率較高。
具體的流程見下圖 gif:
[圖片上傳失敗...(image-1b5dc0-1649294241692)]
想法
關(guān)于上述的內(nèi)容颁督,Hudi 自身提供了一個比較便捷的 Docker Demo践啄,讓用戶可以很快地上手。
談到數(shù)據(jù)湖框架沉御,大家都會說出現(xiàn)在比較流行的三個開源軟件屿讽,分別為 Delta Lake、Apache Hudi 和 Apache Iceberg吠裆。雖然經(jīng)常把他們拿來一起比較伐谈,但是實際上每個框架的背景都是不一樣的烂完。
比如 Iceberg 的初衷是解決 Netflix 內(nèi)部文件格式混亂的問題,Hive Table 中即可能是 csv衩婚,也可能是 parquet 文件格式窜护,用戶在做一些 metadata 的修改時,需要清楚的知道自己所操作 Table 的很多屬性非春,針對這個痛點柱徙,Iceberg 提出了 everything can be a table 的概念,期望用 Iceberg Table 來統(tǒng)一所有的 Table奇昙。
而 Hudi 提出的則是批流兩種計算模型的折中方案护侮,Delta 我了解的不算太多,但是總體跟 Hudi 比較類似储耐。目前 Apache Iceberg 也在積極地做 Row-Level Update羊初,也就是類似 Hudi 的 upsert 功能。
雖然出發(fā)點不同什湘,但是三種框架無一例外都是指向了 Hive 這個統(tǒng)治數(shù)倉數(shù)十年长赞,但是數(shù)十年來變化并不大的框架,隨著數(shù)十年來 Hadoop 生態(tài)的發(fā)展闽撤,Hadoop 生態(tài)支持的數(shù)據(jù)量得哆、數(shù)據(jù)類型都有一個很大的提升,以 Hive 做數(shù)倉必然是比較簡單哟旗,但是 Hive 本身對 Table 中的內(nèi)容掌控度是比較小的贩据。以倉儲為例,Hive 相當于只是提供了一個倉庫闸餐,但是沒有利用倉庫中的內(nèi)容去做一些優(yōu)化饱亮,大家只是把東西放到倉庫里,但是倉庫的東西一多舍沙,大家找東西就會比較亂近上,而新興的數(shù)據(jù)湖框架,既提供了一個倉庫的功能拂铡,同時還給倉庫配上了標簽信息戈锻、監(jiān)控工具、智能運輸?shù)裙δ芎拖保词箓}庫裝的很滿格遭,用戶也可以輕松根據(jù)標簽定位到具體的貨架。