Apache Iceberg 中文教程4-维护Maintenance
维护
维护操作需要Table实例。请参考Java API快速入门页面,了解如何加载现有表格。
推荐的维护操作
过期快照
每次对Iceberg表进行写入都会创建一个新的快照,或者说是表的一个版本。快照可以用于时间旅行查询,也可以将表回滚到任何有效的快照。
建议定期过期快照,以删除不再需要的数据文件,并保持表元数据的大小。
以下示例过期超过1天的快照:
Table table = ...;
long tsToExpire = System.currentTimeMillis() - (1000 * 60 * 60 * 24); // 1天
table.expireSnapshots()
.expireOlderThan(tsToExpire)
.commit();
还有一个针对大型表并行运行表过期的Spark操作:
Table table = ...;
SparkActions
.get()
.expireSnapshots(table)
.expireOlderThan(tsToExpire)
.execute();
过期旧的快照会从元数据中删除它们,因此它们将不再可用于时间旅行查询。只有当不再有可能使用于时间旅行或回滚的快照引用时,才会删除数据文件。定期过期快照可以删除未使用的数据文件。
删除旧的元数据文件
Iceberg使用JSON文件跟踪表的元数据。对表进行的每个更改都会产生一个新的元数据文件,以提供原子性。
默认情况下,旧的元数据文件被保留用于历史记录。频繁提交的表(例如由流式作业编写的表)可能需要定期清理元数据文件。
要自动清理元数据文件,请在表属性中设置write.metadata.delete-after-commit.enabled=true
。这将保留一些元数据文件(最多write.metadata.previous-versions-max
个),并在创建新的元数据文件后删除最旧的元数据文件。
属性说明:
write.metadata.delete-after-commit.enabled
:是否在每次提交表格后删除旧的跟踪元数据文件write.metadata.previous-versions-max
:要保留的旧元数据文件数量
请注意,这仅会删除在元数据日志中跟踪的元数据文件,并不会删除孤立的元数据文件。例如,如果write.metadata.delete-after-commit.enabled=false
且write.metadata.previous-versions-max=10
,在100次提交之后,您将拥有10个被跟踪的元数据文件和90个孤立的元数据文件。配置write.metadata.delete-after-commit.enabled=true
和write.metadata.previous-versions-max=20
不会自动删除元数据文件。当达到write.metadata.previous-versions-max=20
时,跟踪的元数据文件将再次被删除。
有关详细信息,请参阅表写入属性。
删除孤立文件
在Spark和其他分布式处理引擎中,任务或作业失败可能会留下未被表元数据引用的文件。在某些情况下,正常的快照过期可能无法确定某个文件不再需要并删除它。
要清理表位置下的这些“孤立”文件,请使用deleteOrphanFiles
操作。
Table table = ...;
SparkActions
.get()
.deleteOrphanFiles(table)
.execute();
有关更多配置选项,请参阅DeleteOrphanFiles Javadoc
。
如果数据和元数据目录中的文件很多,此操作可能需要很长时间才能完成。建议定期执行此操作,但您可能不需要经常执行此操作。
如果将保留间隔设置为小于预计的写入完成时间,可能会损坏表格,因为正在进行的文件可能被视为孤立文件并被删除。默认间隔为3天。
Iceberg在确定哪些文件需要删除时使用路径的字符串表示。在某些文件系统中,路径可能会随时间而变化,但仍然表示相同的文件。例如,如果更改了HDFS集群的权限,则在创建期间使用的旧路径URL将与当前列表中显示的路径不匹配。当运行RemoveOrphanFiles
时,这将导致数据丢失。请确保MetadataTables中的条目与Hadoop FileSystem API列出的条目匹配,以避免意外删除。
可选的维护操作
有些表需要额外的维护工作。例如,流式查询可能会产生小的数据文件,这些文件应该合并为更大的文件。而且,一些表可以通过重写清单文件来加快查询中数据的定位速度。
压缩数据文件
Iceberg跟踪表中的每个数据文件。更多的数据文件意味着在清单文件中存储更多的元数据,而小的数据文件会导致不必要的元数据和从文件打开成本角度来看查询效率低下。
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();
文件元数据表对于检查数据文件大小并确定何时压缩分区非常有用。
查看RewriteDataFiles Javadoc
以了解更多配置选项。
重写清单
Iceberg使用其清单列表中的元数据来加速查询计划并剪枝不必要的数据文件。元数据树充当表数据的索引。
元数据树中的清单会按照添加的顺序自动压缩,这样当写入模式与读取过滤器对齐时,查询会更快。例如,将按小时分区的数据写入时,与时间范围查询过滤器对齐。
当表的写入模式不与查询模式对齐时,可以使用rewriteManifests
或rewriteManifests
操作(使用Spark进行并行重写)重新组织数据文件并将其编组到清单中。
此示例将重写小的清单,并按第一个分区字段对数据文件进行分组。
Table table = ...
SparkActions.get().rewriteManifests(table)
.rewriteIf(file -> file.length() < 10 * 1024 * 1024) // 10 MB
.execute();
查看RewriteManifests Javadoc
以了解更多配置选项。