读写
每次 Iceberg 的写操作,只有发生 commit 之后,才是可读的;如有多个线程同时在读,但一部分线程在写,可以实现:只有 commit 完整的数据之后,对用户的读操作才能被用户的读线程所看到,实现读写分离。
例如上图中,在对 S3 进行写操作的时候,S2、S1 的读操作是不受影响的;此时 S3 无法被读到,只有 commit 之后 S3 才会被读到。此时 Current Snapshot 会指向 S3。
Iceberg 默认从最新 Current Snapshot 读取数据;如果读更早的数据,可指定对应的Snapshot 的 id ,实现数据回溯。
事务性提交
写操作:记录当前元数据的版本——base version,创建新的元数据以及 manifest 文件,原子性将 base version 替换为新的版本。
原子性替换:原子性替换保证了线性历史,通过元数据管理器所提供的能力,以及 HDFS 或本地文件系统所提供的原子化 rename 能力实现。
冲突解决:基于乐观锁实现,每一个 writer 假定当前没有其他的写操作,对表的 write 进行原子性的 commit,若遇到冲突则基于当前最新的元数据进行重试。
分区裁剪
直接定位到 parquet 文件,无需调用文件系统的 list 操作。
Partition 的存储方式对用户透明,用户在修改 partition 定义时,Iceberg 可以自动地修改存储布局,无需用户重复操作。
谓词下推
Iceberg 会在两个层面实现谓词下推:
在 snapshot 层面,过滤掉不满足条件的 data file。
在 data file 层面,过滤掉不满足条件的数据。
其中,snapshot 层面的过滤操作为 Iceberg 所特有,正是利用到 manifest 文件中的元数据信息,逐字段实现文件的筛选,大大地减少了文件的扫描量。而同为 Table Format 产品、在字节其他业务产线已投入使用的 Hudi,虽然同样具备分区剪枝功能,但是尚不具备谓词下推功能。