这是我参与「第四届青训营 」笔记创作活动的第12天
数据湖三剑客:Delta Lake、Hudi 与 Iceberg 详解
数据湖
数据湖是一类存储数据自然/原始格式的系统或存储,通常是对象块或者文件。数据湖通常是企业中全量数据的单一存储。 全量数据包括原始系统所产生的原始数据拷贝以及为了各类任务而产生的转换数据,各类任务包括报表、可视化、高级分析和机器学习。
数据湖的架构发展
数据湖可以认为是新一代的大数据基础设施。
第一阶段:以Hadoop为代表的离线数据处理基础设施
Hadoop是以HDFS为核心存储,以MapReduce(简称MR)为基本计算模型的批量数据处理基础设施。
第二阶段:Lambda架构
随着数据处理能力和处理需求的不断变化,越来越多的用户发现,批处理模式无论如何提升性能,也无法满足一些实时性要求高的处理场景,流式计算引擎应运而生,例如Storm、Spark Streaming、Flink等。
Lambda架构的核心理念是“流批一体”,如上图所示,整个数据流向自左向右流入平台。进入平台后一分为二,一部分走批处理模式,一部分走流式计算模式。无论哪种计算模式,最终的处理结果都通过服务层对应用提供,确保访问的一致性。
第三阶段:Kappa架构
Lambda架构解决了应用读取数据的一致性问题,但是“流批分离”的处理链路增大了研发的复杂性。因此,有人就提出能不能用一套系统来解决所有问题。目前比较流行的做法就是基于流计算来做。流计算天然的分布式特征,注定了他的扩展性更好。通过加大流计算的并发性,加大流式数据的“时间窗口”,来统一批处理与流式处理两种计算模式。
现在的数据湖都是湖仓一体的,结合了数据湖和数据仓库的优势,将数据仓库中对于数据的严格管理直接实现到了低成本的分布式存储之上
核心技术
Time Travel
每次写入都生成一个新的元数据文件,记录变更。分区数据在update时,不要删除旧数据,保证新旧共存。元数据中存储具体的文件路径,而不仅仅是分区文件夹
实现:每一次写入操作,创建一个新的json文件,以递增版本号命名,记录本次新增/删除的文件;每当产生N个json,做一次聚合,记录完整的分区文件信息;用checkpoint记录上次做聚合的版本号

Transaction
数据湖中的ACID
-
原子性(Atomicity) :本次写入要么对用户可见,要么不可见(需要设计)
-
一致性(Consistency) :输入是什么,落盘就是什么(由计算引擎保证)
-
隔离性(Isolation): 正确解决读写冲突和写写冲突(需要设计)
-
持久性(Durability): 落完数据后,即便服务器重启结果不变(由存储引擎保证)
原子性(Atomicity)
写入流程:先写parquet数据文件,再写json元数据文件
如何确保原子性?
需要从用户可见性入手,用户只会读取以版本号数据命名的json文件,每次都读取到最大的版本号作为数据集的现状。新的写入写完parquet后开始写json文件,使用hash值对json文件命名。直到json文件内容写入完毕,利用hdfs的renameIfAbsent能力将hash值文件名替换为数字文件名,到此为止,commmit完成,新的读取将以数字文件名作为最新版本。
这样读写冲突就已经解决,新的写入除非commit,否则用户读不到;用户正在读的分区,被另一个写入进行了更新,数据不会进行替换,而是共存。
事务隔离(Isolation)
update写入流程
- 从最新的版本中,获取需要update的分区
- 乐观锁先把该写入的文件全落盘,然后进入写json阶段
分一下情况讨论:
- 发现版本号和一开始没区别,直接写新的版本
-
发现版本号增加了,看看新增的这些版本有没有更新我要更新的分区
- 没有,直接写新版本
- 有,两者都更新了同一分区,重新update
Schema Evolution
Add/Drop/Rename
重要:用户并不直接读取parquet文件本身,而是通过数据湖接口读取,如Dataset<Row> ds = simpleDataLake.read(mytable).option(date=2020-01-01)。数据湖内部会读取应该读的parquet,并在schema上做进一步处理
ID将data和metadata的列名做一一对应,存在以下情况:
-
唯一确定的ID。新增列赋予新ID。删列ID不复用。
-
写入数据后,ID也写入数据文件
-
读取数据时,用ID做映射,如果
- data中没有,metadata中有:ADD
- data中有,metadata中没有:DROP
- data和metadata中都有同一ID,但是name不同:RENAME
Iceberg、Hudi、Delta Lake对比

技术选型
我们要根据实际情况来选择,短期来看:每个项目都有一些属于自己的功能:
- 如果强需求upsets,Hudi是最好的选择。
- 如果希望可扩展性强,那么设计优良的Iceberg是最好的选择
- 如果希望用上Z-Order等优化,那么就掏钱买Databricks的企业版Delta
长期来看:数据湖取代Hive,成为HDFS上的表格式标准是必然的,在选择之前问自己四个问题
- 我需要的feature在哪个数据湖上最稳定
- 哪一个数据湖能够用最简单的加入方式(SQL),用上最完善的功能
- 哪一个数据湖有计算引擎侧的支持和社区的支持
- 哪一个数据湖的版本管理做的最好,最鲁棒
总结
数据湖的最新发展状态时湖仓一体,数据湖以低存储成本提供了ACID Transaction、Schema evolution、 Time traverl等高级功能。