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

134 阅读7分钟

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

本节课程目录:

  1. 发展历史
  2. 核心技术
  3. 各有所长
  4. 总结场景

1. 发展历史

1.1 数据湖发展阶段 - Hadoop

image.jpeg

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

image.png

1.2 数据湖发展阶段 - Hive

image-2.png

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

image-2.jpeg

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

什么是数据仓库?

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

image-3.png

image-5.png

湖仓一体(数据湖的现状)

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

image-4.png

1.4 业界三大数据湖

Uber

  • 国外版滴滴,打车软件
  • 在行程规划、拼车、顺风车等业务上数据量很大
  • 数据写入面临挑战

Apache Hudi

  • 最初希望解决的问题:使数据写入能够更低延迟

NETFLIX

  • 流媒体
  • 存储用户观看数据,推荐剧集

ICEBERG

  • 最初希望解决的问题:摆脱 Hive 架构带来的问题

Databricks

  • 起源于 UCB,参与 Spark 的制作
  • 超级独角兽
  • 主打湖仓一体

Delta Lake

1.5 关于“数据湖”

  • 数据相关概念比较新,一直处在演进当中
  • 一开始是 HDFS,裸 pd,txt 日志等,叫数据湖
  • 后来出现了 Iceberg,Hudi,Delta Lake了,数据湖概念就基本等于这些产品
  • 更贴近于 Lakehouse 的概念

2. 核心技术

2.1 文件结构

写入数据湖时:

  1. 按照每条数据的 date 进行分区
  2. 额外使用 metadata 文件记录表信息

image-6.png

2.2 Time travel

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

image-8.png

  1. 每一次写入操作,创建一个新的 json 文件,以递增版本号命名,记录本次新增/删除的文件
  2. 每当产生 N 个 json,做一次聚合,记录完整的分区文件信息
  3. 用 checkpoint 记录上次做聚合的版本号

2.3 Transaction

ACID 是指数据库在写入或更新资料的过程中,为保证事务是正确可靠的,所必须具备的四个特性。

  • Atomicity:原子性 —— 本次写入要么对用户可见,要么不可见(需要设计)
  • Consistency:一致性 —— 输入是什么,落盘的就是什么(由设计引擎保证)
  • Isolation:事务隔离 —— 正确解决读写冲突和写写冲突(需要设计)
  • Durability:持久性 —— 落完数据后,即便服务器重启结果不变(由存储引擎保证)

2.3.1 原子性 Atomicity

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

2.3.2 事务隔离 Isolation

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

截屏2022-08-09 10.08.35.png

2.4 Schema Evolution

Add/Drop/Rename

  • 用户并不直接读取 parquet 文件本身,而是通过数据湖借口读取,如 <Row> ds = dimpleDataLake.read(mytable).option(data=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

3. 各有所长

3.1 Iceberg 工作重点

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

3.1.1 Well-designed Metadata Layer

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

image-10.png

3.1.2 Data File Filter

一些有助于 filter 的数据被层层记录

  1. Manifest file 记录了每个 data file 的分区范围
  2. Manifest list 记录了每个 manifest file 的分区范围,分区可以被快速定位,可以做 manifest list 级别裁剪
  3. Manifest file 记录了每个 data file 每一列的最大值。最小值可以通过其他的列做 data file 级别裁剪

3.1.3 Hidden Partition

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

3.2 Hudi

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 Service
  6. 完全开源,由 Apache 孵化

3.2.1 Timeline Service & Upsert & Incremental

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

image-11.png

3.2.2 Copy on Write

image-13.png

3.2.3 Merge on Read

image-12.png

3.3 Delta Lake 工作重点

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

3.3.1 流批一体

image-15.png

image-14.png

4. 总结场景

4.1 三个数据湖的异同

image-16.png

4.2 三个数据湖的热度

image-17.png

image-18.png

4.3 技术选型

短期来看:每个项目都有一些属于自己的功能

  • 如果强需求 Upserts,也许 Hudi 是最好的选择
  • 如果希望可扩展性强,设计优良的 Iceberg 是最好的选择
  • 如果希望用上 Z-Order 等优化,那么买 Databricks 的企业版 Delta 是不二之选

长期来看:数据湖取代 Hive,成为 HDFS 上的表格式标准是必然的,在选择之前问自己四个问题:

  1. 我需要的 feature 在那个数据湖上是最稳定的

  2. 哪一个数据湖能够用最简单的接入方式 SQL 用上最完善的功能

  3. 哪一个数据湖有计算引擎侧的支持和社区的支持

  4. 哪一个数据湖的版本管理做的最好最棒