歡迎關(guān)注公眾號(hào)“Tim在路上”
剛剛結(jié)束的Data + AI summit上岳遥,Databricks宣布將Delta Lake全部開源。
目前在LakeHouse的市場(chǎng)上國(guó)內(nèi)有Hudi聊记,國(guó)外有Iceberg, Delta Lake社區(qū)正被他們沖擊著,這次Delta Lake的全部開源不管是急病亂投醫(yī)恢暖,還是絕地反擊我們暫不討論排监。今天我們主要來了解了Delta Lake是如何實(shí)現(xiàn)的。
Delta Lake的誕生
在2017年杰捂,Delta Lake 橫空出世舆床,它主打的概念是湖倉(cāng)一體,最初只開放給付費(fèi)用戶使用。在2019年時(shí)挨队,為提高其市場(chǎng)的占用份額和影響力谷暮,將其進(jìn)行部分開源。
Delta Lake創(chuàng)建之初的定位主要是為解決云存儲(chǔ)中很難實(shí)現(xiàn) ACID 事務(wù)和高性能的問題盛垦。
- 更新不是原子操作湿弦,因此查詢不是隔離的,那么在多對(duì)象的更新中腾夯,reader將可以查詢到部分的更新颊埃,某個(gè)對(duì)象更新失敗后回滾需要整體回滾。
- 在大型表的云存儲(chǔ)中進(jìn)行元數(shù)據(jù)操作成本很高蝶俱。例如parquet文件的footer中包含min/max統(tǒng)計(jì)信息可以幫助reader進(jìn)行選擇性的讀取班利,在HDFS上讀取這樣的頁(yè)腳可能需要幾毫秒,但是在云存儲(chǔ)上需要更高的讀取延時(shí)跷乐。
- 對(duì)象存儲(chǔ)上的list操作性能非常差肥败。
為了解決上面的問題,設(shè)計(jì)并實(shí)現(xiàn)了基于云存儲(chǔ)的ACID表存儲(chǔ)層--Delta Lake愕提。
Delta Lake的實(shí)現(xiàn)思想也很簡(jiǎn)單:使用存儲(chǔ)在云對(duì)象存儲(chǔ)中的預(yù)寫日志,以ACID的方式來管理維護(hù)Delta表中的信息皿哨。
那么Delta Lake是如何解決上面的存儲(chǔ)層問題呢浅侨?我列舉了如下幾個(gè)重要的特性:
- 時(shí)間旅行,允許用戶查詢時(shí)間點(diǎn)的快照证膨,也可以根據(jù)時(shí)間點(diǎn)進(jìn)行回滾如输。
- Upsert、Delete和Merge操作央勒,可以有效的重寫對(duì)象不见,支持流式更新操作。
- 高效的流式IO, 通過流式操作將小對(duì)象寫入表中崔步,并以事務(wù)的方式進(jìn)行合并更新稳吮,同時(shí)還支持增量消費(fèi)。
- 自動(dòng)的數(shù)據(jù)布局優(yōu)化井濒,可以自動(dòng)的優(yōu)化表中的對(duì)象大小灶似,并將數(shù)據(jù)記錄進(jìn)行聚類。
- 支持schema進(jìn)化瑞你,支持表的schema更改但不用重寫他們酪惭。
Delta Lake的存儲(chǔ)架構(gòu)
Delta Lake 的數(shù)據(jù)存儲(chǔ)原理其實(shí)很簡(jiǎn)單。它通過 Partition Directories 存儲(chǔ)數(shù)據(jù)者甲,數(shù)據(jù)格式推薦為 Parquet春感,然后通過預(yù)寫的 Transaction Log (事務(wù)日志)記錄的表版本(Table Version) 和變更歷史,以維護(hù)歷史版本數(shù)據(jù)。
Delta Lake中的一些表級(jí)的操作鲫懒,例如更新元數(shù)據(jù)纺铭、更新表名、變更 Schema刀疙、增加或刪除Partition舶赔、添加或者移除文件,都會(huì)以日志的形式將所有的操作存儲(chǔ)在表中谦秧。
上圖展示了Delta中數(shù)據(jù)的組織形式竟纳。數(shù)據(jù)和事務(wù)日志都被存儲(chǔ)在表級(jí)的目錄下,其中數(shù)據(jù)以傳統(tǒng)的Hive分區(qū)目錄的方式存儲(chǔ)疚鲤,事務(wù)日志被存儲(chǔ)在_delta_log的目錄下锥累。
- Delta每次事務(wù)commit都會(huì)產(chǎn)生一個(gè)json的元數(shù)據(jù)文件,文件內(nèi)容包括本次commit做的所有action集歇,比如AddFile/RemoveFile桶略,也包括對(duì)schema的修改等等;
- 每產(chǎn)生一個(gè)新的json文件就會(huì)產(chǎn)生一個(gè)新的Delta的snapshot,snapshot的版本即該json文件中的數(shù)字诲宇,該數(shù)字必須是連續(xù)自增际歼,Delta的某個(gè)版本的snapshot是通過順序回放所有小于等于該snapshot版本號(hào)的所有json文件得到;
- Delta Lake會(huì)以一定的頻率做checkpoint,checkpoint以Parquet的格式存儲(chǔ)姑蓝,目的是為了便于使用Spark并行進(jìn)行向量化處理鹅心。
- delta_log子目錄下還包含一個(gè)last_checkpoint文件指向最新的checkpoint,從而在日志操作時(shí)可以快速找到最新的checkpoint纺荧。
從上面的元數(shù)據(jù)結(jié)構(gòu)可以看出旭愧,Delta和Hudi和Iceberg其實(shí)是大同小異。
那么Delta基于事務(wù)日志實(shí)現(xiàn)的細(xì)節(jié)又是怎樣的呢宙暇?
Delta事務(wù)日志的實(shí)現(xiàn)細(xì)節(jié)
Delta事務(wù)日志的實(shí)現(xiàn)主要是基于MVCC多版本控制協(xié)議實(shí)現(xiàn)输枯。Delta 的 MVCC 算法保留多個(gè)數(shù)據(jù)副本,而不是立即替換包含正在更新或刪除的記錄的文件占贫。
表的讀忍蚁ā:主要是通過使用事務(wù)日志有選擇地選擇要處理的數(shù)據(jù)文件,確保他們一次只能看到表的一致快照靶剑。
表的寫入與修改:首先蜻拨,樂觀地寫出新數(shù)據(jù)文件或修改現(xiàn)有數(shù)據(jù)文件的拷貝副本。然后桩引,進(jìn)行事務(wù)提交缎讼,通過向日志中添加新條目來創(chuàng)建表的最新原子版本。在此日志條目中坑匠,他們記錄了要在邏輯上添加和刪除哪些數(shù)據(jù)文件血崭,以及對(duì)有關(guān)表的其他元數(shù)據(jù)的更改。
在用戶指定的保留期(默認(rèn)為 7 天)后,過期的數(shù)據(jù)文件將被刪除夹纫。
- Delta files
./_delta_log/00000000000000000001.json
Delta files是以原子性單位產(chǎn)生的文件(即沒提交一次commit事務(wù))咽瓷,文件的命名是遞增的版本id, 它與checkpoints文件一起構(gòu)成表中所有更改的日志。
Delta files的json文件中會(huì)包含一組應(yīng)用應(yīng)用于前一個(gè)表版本的actions操作舰讹,每一個(gè)actions是以一個(gè)json組存儲(chǔ)與Delta files中茅姜。
其action行為主要有以下幾種:SetTransaction、AddFile月匣、RemoveFile钻洒、Metadata、Protocol锄开、CommitInfo和Column Mapping素标。
- Checkpoints
./_delta_log/00000000000000000010.checkpoint.parquet
checkpoints文件也存儲(chǔ)在 _delta_log 目錄中,可以為任何版本的表創(chuàng)建萍悴。檢查點(diǎn)包含在此版本之前的所有操作的完整回放头遭,并刪除了無效操作。無效操作是那些已被后續(xù)操作取消的操作(例如刪除已添加的文件)癣诱。
默認(rèn)情況下计维,參考實(shí)現(xiàn)每 10 次提交創(chuàng)建一個(gè)checkpoint。checkpoints文件名基于檢查點(diǎn)包含的表的版本狡刘。
- 最后一個(gè)Checkpoint
Delta 事務(wù)日志通常包含許多(例如 10,000+)文件享潜。列出如此大的目錄可能會(huì)非常昂貴。最后一個(gè)checkpoint文件可以通過提供指向日志末尾附近的指針來幫助降低構(gòu)建表的最新快照的成本嗅蔬。
讀者可以通過查看_delta_log/_last_checkpoint
文件來定位最近的檢查點(diǎn),而不是列出整個(gè)目錄疾就。
那么接下來我們來看看json文件中的內(nèi)容是什么澜术?下面我們撿幾個(gè)重要的展開看看。
Actions
- Metadata
元數(shù)據(jù)操作更改表的當(dāng)前元數(shù)據(jù)猬腰。表的第一個(gè)版本必須包含元數(shù)據(jù)操作鸟废。隨后的元數(shù)據(jù)操作完全覆蓋表的當(dāng)前元數(shù)據(jù)。
{
"metaData":{
"id":"af23c9d7-fff1-4a5a-a2c8-55c59bd782aa",
"format":{"provider":"parquet","options":{}},
"schemaString":"...",
"partitionColumns":[],
"configuration":{
"appendOnly": "true"
}
}
}
Metadata中記錄當(dāng)前表id, 表級(jí)別的file format, 分區(qū)列信息等姑荷。在schemaString存儲(chǔ)這columnMapping信息盒延。使用列映射來避免任何列命名限制,并支持重命名和刪除列鼠冕,而無需重寫所有數(shù)據(jù)添寺。列映射有三種模式,按名稱和按id和none懈费。
{
"name" : "e",
"type" : {
"type" : "array",
"elementType" : {
"type" : "struct",
"fields" : [ {
"name" : "d",
"type" : "integer",
"nullable" : false,
"metadata" : {
"delta.columnMapping.id": 5,
"delta.columnMapping.physicalName": "col-a7f4159c-53be-4cb0-b81a-f7e5240cfc49"
}
} ]
},
"containsNull" : true
},
"nullable" : true,
"metadata" : {
"delta.columnMapping.id": 4,
"delta.columnMapping.physicalName": "col-5f422f40-de70-45b2-88ab-1d5c90e94db1"
}
}
- ADD / Delete File
添加和刪除操作分別用于通過添加或刪除單個(gè)數(shù)據(jù)文件來修改表中的數(shù)據(jù)计露。
{
"add": {
"path":"date=2017-12-10/part-000...c000.gz.parquet",
"partitionValues":{"date":"2017-12-10"},
"size":841454,
"modificationTime":1512909768000,
"dataChange":true
"stats":"{\\"numRecords\\":1,\\"minValues\\":{\\"val..."
}
}
add中記錄添加文件的相對(duì)路徑,以及當(dāng)前file所屬的分區(qū)信息,通過還包含了file的統(tǒng)計(jì)信息票罐,包括min/max叉趣。
{
"remove":{
"path":"part-00001-9…..snappy.parquet",
"deletionTimestamp":1515488792485,
"dataChange":true
}
}
刪除操作只包括一個(gè)時(shí)間戳,指示刪除發(fā)生的時(shí)間该押。文件的物理刪除可能會(huì)延遲進(jìn)行在用戶指定的過期時(shí)間之后疗杉。刪除操作應(yīng)該作為邏輯刪除保持在表的狀態(tài)中,直到過期蚕礼。當(dāng)增量文件的創(chuàng)建時(shí)間戳超過添加到刪除操作時(shí)間戳的過期閾值時(shí)烟具,邏輯刪除將過期。
- Transaction Identifiers
{
"txn": {
"appId":"3ba13872-2d47-4e17-86a0-21afd2a22395",
"version":364475
}
}
事務(wù)標(biāo)識(shí)符以appId版本對(duì)的形式存儲(chǔ)闻牡,其中appId是修改表的進(jìn)程的唯一標(biāo)識(shí)符净赴,版本表示該應(yīng)用程序取得了多大進(jìn)展。該信息的原子記錄以及對(duì)表的修改使這些外部系統(tǒng)能夠?qū)⑵鋵懭氲紻elta表冪等中罩润。
下面我們來總結(jié)對(duì)比下:
- Delta的實(shí)現(xiàn)和Spark深度綁定玖翅,雖然delta2.0官宣支持多種引擎,但I(xiàn)ceberg和Hudi早已可以支持多種引擎割以,另外iceberg不和任何引擎綁定金度。
- 目前Delta只支持COW形式,Iceberg和Hudi都支持部分MOR严沥。
- 在實(shí)現(xiàn)方式上與Hudi, Iceberg大同小異猜极,但是其事務(wù)日志文件中只記錄了上一版本與當(dāng)前版本的差分Action。如果要獲取某個(gè)commit的完整文件列表就需要把之前的差分Action進(jìn)行重放消玄。不過Delta引入checkpoint機(jī)制跟伏,當(dāng)commit積累到一定數(shù)量,會(huì)生成一個(gè)checkpoint, 此時(shí)會(huì)刪除簡(jiǎn)化無效的Action, 后續(xù)的讀取可以基于這個(gè)checkpoint開始重放翩瓜。
- Delta可以生成較少的元數(shù)據(jù)文件受扳,基于checkpoint機(jī)制和過期文件的刪除,減少了大量小文件的產(chǎn)生兔跌,但是并不能很好獲取某個(gè)commit的數(shù)據(jù)勘高。Iceberg可能會(huì)產(chǎn)生大量的元數(shù)據(jù)文件,影響了查詢性能坟桅,但也相應(yīng)的增加文件組跳過的能力华望。
后續(xù)會(huì)再繼續(xù)解密下開源的付費(fèi)功能Z-order的實(shí)現(xiàn)源碼。