背景
隨着大數據領域的不斷發展, 越來越多的概念被提出並應用到生產中而數據湖概念就是其中之一, 其概念參照阿里雲的簡介: 數據湖是一個集中式存儲庫, 可存儲任意規模結構化和非結構化數據, 支持大數據和AI計算.數據湖構建服務(Data Lake Formation, DLF)作為雲原生數據湖架構核心組成部分, 幫助用戶簡單快速地構建雲原生數據湖解決方案. 數據湖構建提供湖上元數據統一管理、企業級權限控制, 並無縫對接多種計算引擎, 打破數據孤島, 洞察業務價值.
數據湖解決方案中關鍵的一個環節就是數據存儲和計算引擎之間的適配. 為了解決這個問題Netflix開發了Iceberg, 目前已經是Apache的頂級項目.
定義
Iceberg是一個面向海量數據分析場景的開放表格式(Table Format). 定義中所說的表格式(Table Format), 可以理解為元數據以及數據文件的一種組織方式, 處於計算框架(Flink, Spark...)之下, 數據文件之上. 如圖所示:
表格式(Table Format)屬於數據庫系統在實現層面上的一個抽象概念, 一般表格式會定義出一些表元數據信息以及API接口, 比如表中包含哪些字段, 表下面文件的組織形式、表索引信息、統計信息以及上層查詢引擎讀取、寫入表中文件的接口.
特性
數據存儲、計算引擎插件化
Iceberg在設計之初的目標就是提供一個開放通用的表格式(Table Format)實現方案.因此, 它不和特定的數據存儲、計算引擎綁定. 目前大數據領域的常見數據存儲(HDFS、S3...), 計算引擎(Flink、Spark...)都可以接入Iceberg. 在生產環境中, 技術人員可以根據公司的實際情況, 選擇不同的組件搭使用.甚至, 可以不通過計算引擎,直接讀取存在文件系統上的數據.
實時流批一體
Iceberg上游組件將數據寫入完成后, 下游組件及時可讀, 可查詢.可以滿足實時場景.並且Iceberg同時提供了流/批讀接口、流/批寫接口. 技術人員可以在同一個流程里, 同時處理流數據和批數據, 大大簡化了ETL鏈路.
數據表演化(Table Evolution)
Iceberg可以通過SQL的方式進行表級別模式演進. 進行這些操作的時候, 代價極低. 不存在讀出數據重新寫入或者遷移數據這種費時費力的操作.
比如在常用的Hive中, 如果我們需要把一個按天分區的表, 改成按小時分區. 此時, 不能再原表之上直接修改, 只能新建一個按小時分區的表, 然后再把數據Insert到新的小時分區表. 而且, 即使我們通過Rename的命令把新表的名字改為原表, 使用原表的上次層應用, 也可能由於分區字段修改, 導致需要修改 SQL. 這樣花費的經歷是非常繁瑣的.
模式演化(Schema Evolution)
Iceberg支持下面幾種模式演化
ADD
向表或者嵌套結構增加新列
Drop
從表中或者嵌套結構中移除一列
Rename
重命名表中或者嵌套結構中的一列
Update
將復雜結構(struct, map<key, value>, list)中的基本類型擴展類型長度, 比如tinyint修改成int.
Reorder
改變列或者嵌套結構中字段的排列順序
這里, 需要注意的是Map結構不支持ADD和Drop.
Iceberg保證模式演化(Schema Evolution)是沒有副作用的獨立操作流程, 一個元數據操作, 不會涉及到重寫數據文件的過程. 具體的如下:
-
增加列時候, 不會從另外一個列中讀取已存在的的數據
-
刪除列或者嵌套結構中字段的時候, 不會改變任何其他列的值
-
更新列或者嵌套結構中字段的時候, 不會改變任何其他列的值
-
改變列列或者嵌套結構中字段順序的時候, 不會改變相關聯的值
在表中Iceberg 使用唯一ID來定位每一列的信息.新增一個列的時候,會新分配給它一個唯一ID, 並且絕對不會使用已經被使用的ID.
使用名稱或者位置信息來定位列的, 都會存在一些問題, 比如使用名稱的話,名稱可能會重復, 使用位置的話, 不能修改順序並且廢棄的字段也不能刪除.
分區演化(Partition Evolution)
Iceberg可以在一個已存在的表上直接修改, 因為Iceberg的查詢流程並不和分區信息直接關聯.
當我們改變一個表的分區策略時, 對應修改分區之前的數據不會改變, 依然會采用老的分區策略, 新的數據會采用新的分區策略, 也就是說同一個表會有兩種分區策略, 舊數據采用舊分區策略, 新數據采用新新分區策略, 在元數據里兩個分區策略相互獨立,不重合.
在技術人員查詢數據的時候, 如果存在跨分區策略的情況, 則會解析成兩個不同執行計划, 如Iceberg官網提供圖所示:
圖中booking_table表2008年按月分區, 進入2009年后改為按天分區, 這兩中分區策略共存於該表中.
得益於Iceberg的隱藏分區(Hidden Partition), 技術人員在寫SQL 查詢的時候, 不需要在SQL中特別指定分區過濾條件, Iceberg會自動分區, 過濾掉不需要的數據.
Iceberg分區演化操作同樣是一個元數據操作, 不會重寫數據文件.
列順序演化(Sort Order Evolution)
Iceberg可以在一個已經存在的表上修改排序策略.修改了排序策略之后, 舊數據依舊采用老排序策略不變.往Iceberg里寫數據的計算引擎總是會選擇最新的排序策略, 但是當排序的代價極其高昂的時候, 就不進行排序了.
隱藏分區(Hidden Partition)
Iceberg的分區信息並不需要人工維護, 它可以被隱藏起來. 不同其他類似Hive 的分區策略, Iceberg的分區字段/策略(通過某一個字段計算出來), 可以不是表的字段和表數據存儲目錄也沒有關系. 在建表或者修改分區策略之后, 新的數據會自動計算所屬於的分區.在查詢的時候同樣不用關系表的分區是什么字段/策略, 只需要關注業務邏輯, Iceberg會自動過濾不需要的分區數據.
PS: 正是由於Iceberg的分區信息和表數據存儲目錄是獨立的, 使得Iceberg的表分區可以被修改,而且不和涉及到數據遷移.
鏡像數據查詢(Time Travel)
Iceberg提供了查詢表歷史某一時間點數據鏡像(snapshot)的能力. 通過該特性技術人員可以將最新的SQL邏輯, 應用到歷史數據上.
支持事務(ACID)
Iceberg通過提供事務(ACID)的機制, 使其具備了upsert的能力並且使得邊寫邊讀成為可能, 從而數據可以更快的被下游組件消費.通過事務保證了下游組件只能消費已commit的數據, 而不會讀到部分甚至未提交的數據.
基於樂觀鎖的並發支持
Iceberg基於樂觀鎖提供了多個程序並發寫入的能力並且保證數據線性一致.
文件級數據剪裁
Iceberg的元數據里面提供了每個數據文件的一些統計信息, 比如最大值, 最小值, Count計數等等. 因此, 查詢SQL的過濾條件除了常規的分區, 列過濾, 甚至可以下推到文件級別, 大大加快了查詢效率.
不足
Iceberg雖然擁有高度抽象和優雅的設計,但是在功能上還不夠完善, 比如行級刪除的能力, FlinkSQL的適配性, FlinkSQL的V2表流式讀取能力, 以及行級更新還存在BUG等等. 不過, 社區方面已經已經在全力完善相關功能.一些生產中需要的重要特性, 已經規划到Iceberg的Roadmap了. 隨着, 相關功能的完善, Iceberg 在國內的前景是非常值得期待的.