可靠性
可靠性
Iceberg 的设计目标是解决运行在 S3 上的 Hive 表所面临的正确性问题。
Hive 表通过用于分区的中心元存储(metestore)和用于单个文件的文件系统来跟踪数据文件。这使得对表内容的原子性修改变得不可能,而且像 S3 这样的最终一致性存储可能会因为需要列出文件来重建表状态而返回不正确的结果。此外,作业规划还必须进行大量缓慢的列举调用:与分区数量成 O(n) 关系。
Iceberg 使用持久化的树结构跟踪每个快照中完整的数据文件列表。每次写入或删除都会生成一个新快照,并尽可能多地复用前一个快照的元数据树,以避免产生大量的写入。
Iceberg 表中的有效快照存储在表元数据文件中,同时还包含对当前快照的引用。提交操作通过原子操作替换当前表元数据文件的路径。这确保了对表数据和元数据的所有更新都是原子的,并且是可串行化隔离的基础。
由此带来了更强的可靠性保证:
- 可串行化隔离:所有表变更都发生在线性的原子表更新历史中
- 可靠的读取:读取方无需加锁即可始终使用一致的表快照
- 版本历史与回滚:表快照作为历史保留,如果作业产生了错误数据,表可以回滚
- 安全的文件级操作:通过支持原子性变更,Iceberg 能够实现新的用例,例如安全地合并小文件、安全地向表追加迟到数据
这种设计还带来了性能上的收益:
- O(1) 的规划 RPC 调用:读取一个快照只需 O(1) 次 RPC 调用,而无需列举表中 O(n) 个目录来规划作业
- 分布式规划:文件裁剪和谓词下推分发到各个作业中,消除了元存储这一瓶颈
- 更细粒度的分区:分布式规划和 O(1) 的 RPC 调用消除了实现更细粒度分区的现有障碍
并发写操作
Iceberg 使用乐观并发支持多个并发写入。
每个写入方假定没有其他写入方在操作,并为某次操作写出新的表元数据。然后,该写入方尝试通过原子地用新表元数据文件替换现有元数据文件来完成提交。
如果原子交换失败(因为其他写入方已经提交),失败的写入方会基于新的当前表状态重新构建元数据树并重试。
重试的开销
写入方通过合理组织变更结构,使工作可以在多次重试之间复用,从而避免代价高昂的重试操作。
例如,追加操作通常会为追加的数据文件创建一个新的 manifest 文件,这样在每次重试时都无需重写 manifest,直接将其添加到表中即可。
重试校验
提交由假设和动作构成。发生冲突后,写入方会检查当前表状态是否满足这些假设。如果假设成立,那么重新执行这些动作并提交就是安全的。
例如,一次压缩可能会将 file_a.avro 和 file_b.avro 重写为 merged.parquet。只要表中仍然同时包含 file_a.avro 和 file_b.avro,提交就是安全的。如果其中任何一个文件已被冲突的提交删除,则该操作必须失败。否则,删除源文件并添加合并后的文件是安全的。
兼容性
由于避免了文件列表列举和重命名操作,Iceberg 表与任何对象存储都兼容。它不要求列表列举的一致性。
评论
登录后参与评论
KnowForge