数据湖三剑客:Delta Lake、Hudi 与 Iceberg 详解 | 青训营笔记

183 阅读9分钟

这是我参与「第四届青训营 」笔记创作活动的的第11天

今天是大数据专场基础班的第十一次课,主要内容是数据湖三剑客:Delta Lake、Hudi 与 Iceberg 详解,主要分为下面四个板块。

一、 发展历史

1. 数据湖发展阶段

image.png

1.1 数据湖发展阶段1 - Hadoop

  • 数据湖最开始的概念——分布式存储HDFS
  • 使用目录来区分不同的数据集
    • /douyin
      • /20220623
      • /20220624
    • /toutiao
  • 好处:
    • 同一公司/组织可以使用共享存储动
    • 数据访问方便,灵活性高
  • 坏处:
  1. 没有记录文件的schema(包括列名、列类型),经常使用Schema on Query的方式
  2. 难以得知数据集包含了那些文件,是通过什么样的分区组织的
  3. 如果多个程序都在修改这个数据集(修改数据、修改表结构),其他程序难以配合做修改

1.2 数据湖发展阶段2- Hive

  • 数据湖的演进——Hive Metastore
  • 对数据湖中的数据集进行集中“定义”
    • 数据湖中存在了哪些数据集
    • 它们都存储在什么目录
    • 数据集的schema是什么样子的
    • 数据集有哪些分区,每个分区的目录是什么

image.png

1.3 数据湖发展阶段3-湖仓一体

  • 什么是数据仓库?
    • 数据仓库将数据从数据源提取和转换,加载到目的地
    • 数据仓库存储+计算不分离
    • 数据仓库严格控制写入数据的schema

image.png

  • 湖仓一体(数据湖的现状):
    • 结合了数据湖和数据仓库的优势
    • 将数据仓库中对于数据的严格管理直接实现到了低成本的分布式存储之上
    • Key Features:
      • Transaction ACID
      • Schema管理
      • 存储计算分离
      • 支持多种计算引擎和文件格式

image.png

1.4 关于“数据湖”

  • 数据相关概念比较新,一直处在演进当中
  • 一开始是 HDFS、裸pb、txt日志等等,叫数据湖(管不动了就叫数据沼泽)
  • 后来出现了了lceberg、Hudi、Delta Lake了,数据湖概念就基本等于这些产品了
  • 也更贴近于Lakehouse的概念

二、 核心技术

1. 文件结构

  • 写入数据湖时
  1. 按照每条数据的date进行分区
  2. 额外使用metadata文件记录表信息,如下图所示

image.png

2. Time travel

  • 要点:
  1. 每次写入都生成一个新的元数据文件,记录变更
  2. 分区数据在Update时,不要删除旧数据,保证新旧共存
  3. 元数据中存储具体的文件路径,而不仅仅是分区文件夹

3. Transaction

  • ACID,是指数据库在写入或更新资料的过程中,为保证事务是正确可靠的所必须具备的四个特性。
  • 以A给B转账10元为例:
  1. Atomicity:原子性——要么A-10 B+10,要么都不变
  2. Consistency:一致性——不可以A-10 B+5
  3. lsolation:事务隔离——A和C同时给B转10,B最终结果应是+20
  4. Durability:持久性——转账服务器重启,结果不变
  • 数据湖中的ACID:
  1. Atomicity: 原子性–本次写入要么对用户可见,要么不可见((需要设计)
  2. Consistency:一致性–输入是什么,落盘的就是什么(由计算引擎保证)
  3. Isolation:事务隔离–正确解决读写冲突和写写冲突(需要设计)
  4. Durability:持久性–落完数据后,即便服务器重启结果不变(由存储引擎保证)

3.1 原子性

  • 写入流程:
  1. 写入parquet数据文件
  2. 写入json元数据文件
  • 如何确保原子性?(从用户可见性入手!)
  1. 用户只会读取以版本号数字命名的json文件,每次都读取到最大的版本号作为数据集的现状
  2. 新的写入写完parquet后开始写json文件,使用hash值对json文件命名,如a2fs4hfg8ee.json
  3. 直到json文件内容写入完毕,利用hdfs的renamelfAbsent能力将a2fs4hfg8ee.json替换为000006.json,到此为止commit完成,新的读取将会以000006.jscn作为最新版本
  • 读写冲突已经被解决,how?
  1. 新的写入除非已经commit,否则用户读不到
  2. 用户正在读的分区,被另一个写入进行了更新,数据不会进行替换,而是共存

3.2 事务隔离

  • Update 写入流程:
  1. 从最新的版本中,获取需要update的分区
  2. 乐观锁先把该写入的文件全落盘,然后进入写json阶段
  3. 分几种情况:
    1. 发现版本号和一开始没区别,直接写新的版本
    2. 发现版本号增加了,看看新增的这些版本有没有更新我要更新的分区?
      1. 没有,直接写新的版本。
      2. 有,两者都更新了同一分区,得重新update 了

image.png

4. Schema Evolution

Add/Drop/Rename

重要:

  • 用户并不直接读取parquet文件本身,而是通过数据湖接口读取,如Dataset < Row > ds =simpleDataLake.read(mytable).option(date=2020-01-01)

  • 数据湖内部会读取应该读的parquet,并在schema上做进─步处理

  • ID将data和metadata的列名做一—对应!

    1. 唯─确定的ID。新增列赋予新ID。删列ID不复用
    2. 写入数据时,ID也写入数据文件
    3. 读取数据时,用ID做映射,如果
      1. Data中没有,metadata中有:ADD
      2. Data中有,metadata中没有:DROP
      3. Data和metadata中都有同一ID,但是name不同:RENAME
      4. 如果都有同一列名,而ID不同?

三、 各有所长

1. lceberg工作重点

  • 用户体验
  1. Schema evolution
  2. Partition evolution
  3. Hidden partition
  4. Time Travel
  5. Version Rollback
  • 性能
  1. 快速file plan
  2. 更多的filter方式
  • 可靠性
  1. ACID Transaction
  • 完全开源,由Apache孵化开发

1.1 Well-designed Metadata Layer

  • Metadata files定义了表结构,存储了snapshot信息,分区列信息等
  • Manifest lists存储了一个snapshot中所有manifest的信息
  • Manifests存储了一些data files的信息
  • Data files就是具体的数据文件

image.png

1.2 Data File Filter

  • 一些有助于filter的数据被层层记录,比如:
  1. Manifest file记录了每个data file的分区范围
  2. Manifest list记录了每个manifest file的分区范围分区可以被快速定位!可以做manifest list 级别裁剪
  3. Manifest file记录了每个data file每一列的最大值,最小值可以通过其他的列(Userld)做data file 级别裁剪

1.3 Hidden Partition

  • 传统的分区方式:
    • 数据中包含了date列,则按照date分区;如果希望按照hour分区,则需要新增hour列
  • lceberg的分区方式:
    • 数据中包含timestamp 列,设置好partition transform方式
      • 设置为date时,iceberg帮你转化为date分区
      • 设置为hour时,iceberg帮你转化为hour分区
      • lceberg记录了这层转化关系,并且按你的需要进行partition evolution

2. vHudi

  • Hadoop Upsert Delete and Incremental

  • Hudi工作重点:

  1. Timeline service: Hudi管理transaction的方式
  2. Hudi Table Type: Copy on Write /Merge on Read
  3. 高效的 Upserts: update or insert
  4. 索引表:快速定位一条数据的位置
  5. Streaming Ingestion Service6.完全开源,由Apache孵化

2.1 Timeline Serivce & Upsert & Incremental

  • Timeline Service: 记录的信息类似于metadata
  • Upsert: 每一条样本都有一个主键PK,当Upsert 一条数据时,如果现有的数据中有这个PK,则update这条数据。否则直接insert这条数据
  • Incremental: 某个时间点后新增的数据

image.png

2.2 Copy on Write

image.png

2.3 Merge On Read

image.png

3. Delta Lake工作重点

  1. ACID Transaction
  2. Schema校验(不是evolution)
  3. 流批一体
  4. Time Travel
  5. Upsert/Delete
  6. Z-Order 优化
  7. 只开源了一部分,由Databricks自己主导开发,Z-order等优化的实现未开源

四、 总结场景

1. 回顾:三个数据湖的异同

image.png

2. 三个数据湖的热度

image.png

image.png

3. 技术选型

  • 短期来看:每个项目都有一些属于自己的功能:
    • 如果强需求Upserts,也许Hudi是最好的选择
    • 如果希望可扩展性强,那么设计优良的lceberg是最好的选择
    • 如果希望用上Z-Order等优化,那么掏钱买Databricks的企业版 Delta是不二之选
  • 长期来看:数据湖取代 Hive,成为HDFS上的表格式标准是必然的,在选择之前问自己四个问题:
  1. 我需要的feature在哪个数据湖上是最稳定的
  2. 哪一个数据湖能够用最简单的接入方式(SQL)用上最完善的功能
  3. 哪一个数据湖有计算引擎侧的支持和社区的支持
  4. 哪一个数据湖的版本管理做的最好

4. 字节跳动数据湖场景举例- Feature Store

  • Feature Store及其平台
    • 基于Apache lceberg 做了大量定制与优化
    • 站内存储约220 PB训练样本
      • 最大单表30PB,15K个特征
      • 相比instance pb样本能节省约30%~50%空间
    • 平台端到端体验完整、用户使用成本低
      • 控制面板、特征监控、数据维护(样本回溯、TTL、脏数据处理等)
    • 对特征回溯及特征调研场景做了专门强化
      • 支持 Update语义操作和数据分支

image.png

image.png

5. 字节跳动数据湖场景举例

  • 批流一体:近实时的数据写入与数据就绪(Readiness)
  1. 例子:消息队列直接入湖、流式 Upsert
  2. 应用:能同时训最新(流式)和历史(批式)
  • 更强的算力:要求更快的读数据
  1. 例子:分布式任务扫描、向量化读与读时合并、统一内存格式(Apache Arrow)
  2. 应用:数据读取不应成为训练瓶颈

引用参考

内容主要参考了赵汉卿老师在「数据湖三剑客:Delta Lake、Hudi 与 Iceberg 详解」课程里所教授的内容,同时也参考了学员手册里第二节的内容,图片来自于老师的PPT,链接如下:

  1. 【大数据专场 学习资料四】第四届字节跳动青训营 - 掘金 (juejin.cn)
  2. 数据湖三剑客:Delta Lake、Hudi 与 Iceberg 详解 - 赵汉卿 - ppt.pptx - 飞书文档 (feishu.cn)