青训营|大数据 数据湖三剑客

94 阅读6分钟

数据湖三剑客:Delta Lake、Hudi与Iceberg详解

发展历史

发展阶段-Hadoop

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

数据湖第二阶段:Hive

  • 数据湖的演进:HiveMetastore
  • 对数据湖中数据进行了集中定义
    • 数据湖中存了哪些数据
    • 它们存在什么目录
    • 数据集的schema是什么样子的
    • 数据集有哪些分区,每个分区的目录是什么样的
  • 坏处
    • 不同用户读写同一个文件得到的内容可能不一样(引入ACID)
    • 不能进行删改,只能把原始表数据读出来重新写

数据湖第三阶段:湖仓一体

数据仓库:

  • 数据仓库将数据从数据源提取和转换,加载到目的地

  • 数据仓库储存+计算不分离

  • 数据仓库严格控制写入的schema 数据仓库 VS 数据湖:

  • 数据仓库成本高,但是数据湖成本低

  • 数据仓库不是储存计算分离,数据湖是储存计算分离

  • 数据仓库有ACID,数据糊没有配ACID

  • 数据仓库不支持ML,数据湖可以储存原始数据,可以支持ML

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

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

关于数据湖:

  • 数据相关概念比较新,一直处在演进中
  • 一开始是HDFS、日志等,后来太难管理变成数据沼泽
  • 后来出现了Delta Lake、Hudi与Iceberg等产品
  • 更贴近于Lakehouse的概念

核心技术

Ex:设计一个简单的数据湖

  • 储存数据
  • 每天写入新数据
  • 用列储存格式(性能好,可以选列) 写入数据湖时:
  • 按照每条数据的date进行分区
  • 额外使用metadata文件记录表信息

TimeTravel

要点:

  • 每次写入都记录一个新的元数据文件,记录变更
  • 分区数据在update时,不要删除旧数据,保证新旧并存
  • 元数据中储存具体的文件路径,而不仅仅是分区文件夹 写入时:
  • 每一次写入操作,创建一个新的json文件,以递增版本号命名,记录本次增删的文件
  • 每当产生N个json时,做一个聚合,记录完整的分区文件信息
  • 用checkpoint记录上次做聚合的版本号 读写重复:

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

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

原子性

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

事物隔离

  • update写入流程:
    • 从最新的版本中,获取需要update的分区
    • 乐观锁先把该写入的文件全部落盘,然后进入到写json阶段
      • 版本号一开始没写,直接写心得版本
      • 版本号增加了,看看有没有更新我要更新的分区
        • 没有,直接写新的版本
        • 有,两者都更新了同一分区,重新update

Schema Evolution

Add/Drop/Rename

  • 用户并不直接读取parquet文件本身,而是通过数据湖接口来读取
  • 数据湖内部会读取应该读的parquet,并在schema上做进一步处理

ID将data和metadata的列名一一对应

  • 唯一确定的ID。新增列赋予新的ID。删列ID不复用
  • 写入数据时,ID也写入数据文件
  • 读取数据时,用ID做映射,如果
    • Data中有,metadata中没有:ADD
    • Data中有,Metadata中有:DROP
    • Data和matedata中有同一ID,但是name不同:Rename
    • 如果列名一样,ID不一样(先删再加,加的时候ID不一样)

各有所长

Iceberg工作重点

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

Well-Designed metadata layer

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

Data File Filter

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

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

Hiden Partition

传统的分区方式

  • 数据中包含了date列,则按照date分区;如果希望按照hour分区,则新增hour列

Iceberg的分区方式

  • 数据中包含timestamp列,设置好partition transform方式
    • 设置为date时,iceberg会帮你转化为date分区
    • 设置hour时,iceberg会帮你转化为hour分区
    • iceberg记录了这层转化关系,并按照你的需要进行partition evolution

Hudi工作重点

  • Timeline Service:Hudi管理transaction的方式
  • Hudi Table Type:Copy on Write/Merge on Read
  • 高效的Upserts:Update or insert
  • 索引表:快速定位一条数据的位置

总结场景