一、概述

Hudi 在处理 Upsert 请求时,会有一个 tagging 过程,主要是给每条数据打标,标明这条数据是 insert 还是 update。这个标签起到以下作用:

  1. 对于 insert 的数据,Hudi 会写入新的 base 文件
  2. 对于 update 的数据,Hudi 会写入新的 delta 文件,文件名使用原数据的 fileId

Hudi 为了快速地确定每条数据到底是 insert 还是 update,减少 tagging 的时间,还引入了索引机制。索引支持三种不同的类型,但每一种类型或多或少都会带来一些成本,或是影响写入性能,或是增加维护成本。

Iceberg 没有 tagging 过程,也无需外部中间件作为索引,但相应的,Iceberg 的 update 和 delete 并不确定想要更新或删除的记录是否存在,无论如何都会在 DeleteFile 里追加一条 delete 记录,至于这条记录是否真的存在,只有在读取时做合并后才知道。

本质上相当于把 tagging 的过程放在了读取阶段,尽管减少了写入时的成本,但会影响读取的效率。

二、实现

2.1. update

对于数据的 update,和 delete 同理,只不过 Iceberg 不仅在 DeleteFile 里写入一条记录删除旧数据,还会在 DataFile 里写入一条新数据的记录,相当于通过 “delete+insert” 来实现 update

和 Hudi 的 mor 表基本思路类似,都是一种 “base+delta” 的方式

2.2. insert

Iceberg 数据写入流程:

  1. 先把数据写入到 data file 文件中
  2. 当一组 data file 文件写完之后,会根据这个 data file 文件中 column 的一些统计信息(如: 每个 column 的 min/max 值),生成一个对应的manifest文件
  3. 然后 Iceberg 把一次写入后涉及到的 manifest 文件组成一个 manifest list,manifest list 文件中也会存入一些相关 manifest 的统计信息(如:分区信息,manifest 有效性)等
  4. 然后按照整个 manifest list 生成一个对应的 snapshot 文件
  5. 生成完 snapshot 文件之后,Iceberg 会把当前 snapshot 的 ID 及存储路径等信息写入到 metadata 文件中
  6. 当一切准备完毕之后,会以原子操作的方式 commit 这个 metadata 文件,这样一次 Iceberg 的数据写入就完成了。随着每次的写入 Iceberg 就生成了如这样的一个文件组织模式。

三、总结

和 Hudi 有所不同,Hudi 通过 Index 的索引机制,在写入时实时判断索引来达到 Upsert 的功能,而 Iceberg 则是通过良好的文件组织形式,在读取时做合并 MOR(Merge-on-Read)的思路,所以 Hudi 对读取友好,而 Iceberg 对写入友好。