数据湖-Iceberg-源码学习-Kernel-Table-事务
一、概述
传统数据湖在数据写入时的事务性支持不够好,随着越来越多的业务关键处理流程移至数据湖,需要一种机制来原子地发布一批数据,即仅保存有效数据,部分失败必须回滚而不会损坏已有数据集。同时查询的结果必须是可重复的,查询端看不到任何部分提取的数据,任何提交的数据都必须可靠地写入。Hudi 提供了强大的 ACID 能力。高效的回滚机制能够保证数据一致性和避免“孤儿文件”或中间状态数据文件残留和产生。
- 原子性: 事务整体是一个工作单元,对数据的修改操作,要么全部执行,要么完全不执行,没有第三种状态。
- 一致性: 在一个事务执行之前和执行之后数据库都必须处于逻辑上的一致性状态,数据在不同的事务中是相同的。
- 隔离性: 并发执行的事务之间是相互隔离的,一个事务内部的状态,对其他事务是不可见的。
- 持久性: 当系统发生故障时,持久性确保已提交事务的更新不会丢失,也就是说一旦一个事务提交,保证数据的改变是永久性的。
ACID 四属性的关系可大概表述为:原子性是要求,一致性是目标,隔离性是手段,持久性是结果。如何做到原子性的隔离是实现事务的重中之重。在宏观上,实现事务特性是通过并发控制。在微观上,实现事务要靠隔离
Iceberg 的 snapshot 和 Hudi 的 cow 表的实现逻辑,思想上是完全相通的
二、设计
2.1. OCC
Iceberg 支持乐观井发控制(OCC)。在乐观井发控制中,Writer 检查是否有重叠的文件,如果存在冲突,使操作失败并重试,Iceberg 通过在更新过程中对元数据文件进行原子交换操作来支持优化井发(OCC)
其工作方式:
- 每次写入都会创建一个新的表快照。
- 然后,Writer 会尝试对一个持有当前快照ID 的特殊值进行比较和交换(CAS)操作。
- 如果在提交过程中没有其他写入者替换快照,则操作成功
- 如果在此期问有另一个写入者进行提交,另一个写入者将不得不重试,直到成功
在分布式文件系统上,如 HDFS,这可以在本地完成。对于 S3,需要一个额外的组件来存储指针(目前只支持 Hive Metastore)
三、总结
3.1.原子性
Iceberg 借助计算引擎的并发机制,将数据文件的写操作并行化,可互不影响地写数据,在提交元数据端(commit 阶段) 根据 Catalog 存储类型的不同,而使用不同的并发控制方式:
Hadoop Catalog 基于文件 $rename$ 提供原子性的保证
JDBCCatalog 通过数据库的 $Lock$ 来提供原子性的保证
HiveCatalog 是通过 HMS 的 $Lock$ 提供原子性的保证
3.2. 隔离型
Iceberg 通过 Snapshot 隔离的方式实现数据的并发批量读写,每个 Snapshot 反映了当前状态发生的数据变更,比如快照发生的时间、增删或者修改的数据内容等,客户端可以通过快照增量消费数据或者回溯历史数据。
3.3. 持久性
快照通过层级的文件组织,所有文件都存储在分布式文件系统或者分布式对象系统
3.4. 一致性
Snapshot 隔离级别指定: 在一个事务中,任何语句读取的数据,是事务一致性的版本。事务一致性是指在事务开始时,在表级别创建数据快照,只能识别其他事务己提交的数据更新。
3.5.存在问题
那如何保证数据文件的写和数据文件元数据提交这两个阶段的原子性呢🤔️?
3.5.1. Flink
Flink 凭借其 Checkpoint 两阶段提交机制,一旦 Flink Checkpoint 成功完成,数据文件和元数据都外可见,否则快照失效。因为快照本身是不变的,所有基于快照的查询看到的结果都一样,因此保证了事务的ACID 属性。











