TT Lab
开始
学习 学习路径 课程

湖仓表格式 — 从元数据理解 Apache Iceberg

Iceberg 从不自己删除任何东西 — 压缩、过期、孤儿文件清理

在 TT Lab 中继续学习

一句话总结

Iceberg 每次提交都只是增加文件和 metadata,所以小文件要用文件合并(rewrite_data_files)来合并,旧快照和只被它们使用的文件要用过期(expire_snapshots)来删除,从未被任何快照指向过的文件要用孤儿文件清理(remove_orphan_files)来清除。三者都无法撤销,所以顺序和余量才是关键。

为什么需要清理

想象一张每 5 分钟由流式加载提交一次的表。一天就是 288 次提交,每个分区几百个小文件,堆积起 288 个快照和 288 个 metadata.json。正如 Maintenance 文档所说,小文件会增加清单中要记录的内容,也会加大每次查询打开文件的成本。而且这些东西没有一样会自己消失。

做了文件合并,空间却没有减少,这一点起初会让人觉得奇怪。文件合并是把小文件重新写成大文件的一次新提交,而旧的小文件仍被旧快照指向,所以还留着。这正是让时间旅行成为可能的那个性质。空间是在让旧快照过期之后才会归还。

工作原理——三件不同的事

操作 作用 能否撤销
rewrite_data_files 读取小文件并重写成大文件,以 replace 快照提交 是提交,所以可以回滚
expire_snapshots 把比标准更旧的快照从 metadata 中去掉,并删除只被它们使用的文件 不可以
remove_orphan_files 在表位置中找出没有被任何 metadata 指向的文件并删除 不可以

文件合并。rewrite_data_files 的默认策略是 binpack,也有 sort(边排序边重写)。目标大小 target-file-size-bytes 遵循表属性 write.target-file-size-bytes(默认 512MB),比目标的 75% 小的文件会成为重写的候选。min-input-files(默认 5)会让凑够这么多文件的一组,无论其他条件如何都被重写。结果是规范所说的 replace 快照——表的数据不变,只是文件变了。

过期。expire_snapshots 会删除比 older_than(默认 5 天前)更旧的快照,但会保留 retain_last(默认 1)个。文档明确了两点:过期绝不会删除仍存活的快照所使用的文件,也不会删除分支或 tag 所指向的快照。所以,在需要回去的时间点打上 tag,那个快照和文件就能挺过过期。反过来,过期之后就无法再时间旅行到那个快照了。

孤儿文件清理。作业失败或在提交竞争中落败时,数据文件会因没能进入任何快照而留下。remove_orphan_files 会列出表位置中的文件,删除 metadata 没有指向的那些。这里有个陷阱:正在使用的文件在提交之前,看上去也像孤儿。Maintenance 文档警告说,如果以短于写入完成所需时间的间隔来删除孤儿,可能会把正在进行中的文件删掉,导致表损坏,因此把默认间隔定为 3 天。实验镜像中的 Spark 过程在此基础上更进一步,干脆拒绝短于 24 小时的间隔。必须养成习惯,先用 dry_run => true 看看会删除什么。

metadata 文件也会堆积。开启表属性 write.metadata.delete-after-commit.enabled(默认 false)后,每次提交都会删除最旧的 metadata 文件,只保留 write.metadata.previous-versions-max(默认 100)个。

在现场相遇的样子

顺序搞反了。运行了过期作业的第二天,才发现还需要回到月末结账的快照。没有办法挽回。要把“在过期之前给结账、发布这类时间点打上 tag”写进流程。

孤儿文件清理破坏了正常的加载。有人说“只保留到昨天的”,把 older_than 缩短为一小时前,恰好一个耗时很长的加载作业的文件被删掉了。如果那个作业提交成功,表就会指向不存在的文件。间隔要比耗时最长的写入更宽裕。

清理作业扰动了表。文件合并也是提交,所以会与加载竞争。要在加载较少的时间运行,失败了下个周期再做就行。

实际工作中真正重要的事

下一项实验要做什么

把 30 个小批次分 30 次提交写入,制造出小文件和快照的堆积,并记录清理前的数字。给第十次提交打上 tag,然后用 rewrite_data_files 做文件合并,用 expire_snapshots 只保留当前快照,确认被 tag 保护的快照和文件依然存活。放一个旧的孤儿文件和一个刚创建的文件,先用 dry_run 运行 remove_orphan_files,看只有旧的被删除,最后解释:清理之后,磁盘上的文件数为什么比当前快照的文件数更多。