维护
维护
信息
维护操作需要 Table 实例。请参阅 Java API 快速入门页面,了解如何加载已有表。
推荐的维护操作
过期快照
对 Iceberg 表的每次写入都会创建该表的一个新快照(即版本)。快照可用于时间旅行查询,也可以将表回滚到任意有效快照。
快照会不断累积,直到通过 expireSnapshots 操作将其过期。建议定期过期快照,以删除不再需要的数据文件,并保持表元数据的体积较小。
以下示例会过期早于 1 天的快照:
Table table = ...
long tsToExpire = System.currentTimeMillis() - (1000 * 60 * 60 * 24); // 1 day
table.expireSnapshots()
.expireOlderThan(tsToExpire)
.commit();更多配置选项请参阅 ExpireSnapshots Javadoc。
此外,还有一个 Spark action 可以针对大型表并行执行表过期清理:
Table table = ...
SparkActions
.get()
.expireSnapshots(table)
.expireOlderThan(tsToExpire)
.execute();过期旧快照会将其从元数据中移除,因此它们将不再可用于时间旅行查询。
信息
数据文件在不再被可能用于时间旅行或回滚的快照引用之前不会被删除。定期过期快照会删除未被使用的数据文件。
删除旧元数据文件
Iceberg 使用 JSON 文件来跟踪表元数据。表的每次变更都会生成一个新的元数据文件,以提供原子性。
默认情况下,旧的元数据文件会被保留以供历史查询使用。对于提交频繁的表(例如由流式作业写入的表),可能需要定期清理元数据文件。
每个元数据文件都在 metadata-log 字段中跟踪较旧的元数据文件。被跟踪的元数据文件数量由 write.metadata.previous-versions-max 定义。
要自动删除较旧的元数据文件,请在表属性中设置 write.metadata.delete-after-commit.enabled=true。这样会保留部分被跟踪的元数据文件(最多为 write.metadata.previous-versions-max),并在每次创建新文件时删除最旧的元数据文件。请注意,这只会在元数据日志中删除被跟踪的元数据文件,不会删除孤立的元数据文件。
未被跟踪的元数据文件也会作为孤立文件删除的一部分被删除。
| 属性 | 默认值 | 说明 |
|---|---|---|
| write.metadata.delete-after-commit.enabled | false | 控制是否在每次表提交后删除最旧的被跟踪版本的元数据文件 |
| write.metadata.previous-versions-max | 100 | 要跟踪的先前版本元数据文件的最大数量 |
示例:
- 当
write.metadata.delete-after-commit.enabled=false且write.metadata.previous-versions-max=10时,在 100 次提交之后,将拥有 10 个被跟踪的元数据文件和 90 个孤立的元数据文件。这 90 个孤立的元数据文件无法通过设置write.metadata.delete-after-commit.enabled=true来删除,因为它们已经不被跟踪了。只能通过孤立文件删除过程来清理它们。 - 当
write.metadata.delete-after-commit.enabled=true且write.metadata.previous-versions-max=20时,在 21 次提交之后,将拥有 20 个被跟踪的元数据文件,最旧的元数据文件会在提交后由写入器删除。每增加一次提交,最旧的元数据文件都会被删除。
更多详情请参阅表写入属性。
删除孤立文件
在 Spark 及其他分布式处理引擎中,任务或作业失败可能会留下未被表元数据引用的文件;在某些情况下,正常的快照过期机制无法判断某个文件已不再需要,也就无法将其删除。
要清理表位置下的这些"孤儿"文件,请使用 deleteOrphanFiles 操作。
Table table = ...
SparkActions
.get()
.deleteOrphanFiles(table)
.execute();参见 DeleteOrphanFiles Javadoc 以查看更多配置选项。
如果数据目录和元数据目录中存在大量文件,此操作可能需要很长时间才能完成。建议定期执行此操作,但执行频率不一定需要很高。
信息
如果保留时间间隔短于任何写入预期的完成时间,那么删除孤立文件是很危险的,因为正在进行中的文件可能被判定为孤立文件并被删除,从而损坏表。默认间隔为 3 天。
信息
Iceberg 在确定哪些文件需要删除时使用的是路径的字符串表示。在某些文件系统上,路径可能随时间发生变化,但它仍然表示同一个文件。例如,如果更改为 HDFS 集群的 authority,创建时使用的所有旧路径 URL 都将无法与当前列表中显示的路径匹配。这将在运行 RemoveOrphanFiles 时导致数据丢失。请务必确保 MetadataTable 中的条目与 Hadoop FileSystem API 列出的条目一致,以避免意外删除。
可选维护
有些表需要额外的维护。例如,流式查询可能会产生较小的数据文件,这些文件应当被合并为更大的文件。还有些表可以通过重写 manifest 文件获益,从而使查询定位数据的速度大幅提高。
合并数据文件
Iceberg 会跟踪表中的每个数据文件。数据文件越多,manifest 文件中存储的元数据就越多;而较小的数据文件会导致元数据数量不必要地增加,并因文件打开开销而降低查询效率。
Iceberg 可以使用 Spark 通过 rewriteDataFiles 操作并行合并数据文件。这会将小文件合并为大文件,从而减少元数据开销和运行时的文件打开成本。
Table table = ...
SparkActions
.get()
.rewriteDataFiles(table)
.filter(Expressions.equal("date", "2020-08-18"))
.option("target-file-size-bytes", Long.toString(500 * 1024 * 1024)) // 500 MB
.execute();files 元数据表可用于查看数据文件大小,并判断何时需要对分区进行合并。
参阅 RewriteDataFiles Javadoc 了解更多配置选项。
重写清单文件(Rewrite manifests)
Iceberg 使用清单列表(manifest list)和清单文件(manifest file)中的元数据来加快查询规划速度,并裁剪掉不必要的数据文件。该元数据树充当表数据的索引。
元数据树中的清单文件会按照其添加顺序自动合并,当写入模式与读取过滤条件一致时,这会使查询更快。例如,按到达时间写入的小时级分区数据就与时间范围查询过滤条件相匹配。
当表的写入模式与查询模式不一致时,可以使用 rewriteManifests 或 rewriteManifests 操作(通过 Spark 实现并行重写)重写元数据,将数据文件重新分组到清单文件中。
此示例重写了较小的清单文件,并按第一个分区字段对数据文件进行分组。
Table table = ...
SparkActions
.get()
.rewriteManifests(table)
.rewriteIf(file -> file.length() < 10 * 1024 * 1024) // 10 MB
.execute();有关更多配置选项,请参阅 RewriteManifests Javadoc。
评论
登录后参与评论
KnowForge