
数据湖湖仓一体大数据【免费下载链接】icebergApache Iceberg项目地址https://gitcode.com/gh_mirrors/iceberg5/iceberg点击查看免费下载导读Iceberg 表每次写入都会产生新的快照snapshot快照既支撑时间旅行查询也会随着写入频次增加而不断累积导致数据文件与元数据文件膨胀。本指南围绕官方维护文档整理出一套完整的表维护方案过期快照清理Expire Snapshots、旧元数据文件清理、孤儿文件删除Delete Orphan Files、数据文件压缩Compact Data Files与 Manifest 重写Rewrite Manifests并深入对应源码说明底层实现原理。读完本文你将掌握如何在 Java API 与 Spark Action 两条路径上执行上述维护操作并理解各操作的安全边界与参数取舍。前置条件获取 Table 实例所有维护操作都以Table实例为入口。无论使用哪个引擎先加载已存在的表// 以 HadoopCatalog 为例 Catalog catalog new HadoopCatalog(catalogConf, warehouse/path); Table table catalog.loadTable(TableIdentifier.of(db, table));使用 Spark 时也可通过SparkSession加载后转换为Table。加载表的完整步骤可参考 Java API 快速入门。推荐维护过期快照Expire SnapshotsIceberg 的每次写入都会生成一个新快照也就是表的一个新版本。快照可被用于时间旅行查询也可以将表回滚到任意有效快照。这些快照会一直累积直到通过expireSnapshots操作将其过期。定期过期快照是推荐操作它既能删除不再需要的数据文件也能让表元数据保持精简。过期 1 天以前的快照Table table ...; long tsToExpire System.currentTimeMillis() - (1000 * 60 * 60 * 24); // 1 天 table.expireSnapshots() .expireOlderThan(tsToExpire) .commit();ExpireSnapshots接口 还提供了更丰富的配置方法作用expireSnapshotId(long snapshotId)精确过期指定 ID 的快照expireOlderThan(long timestampMillis)过期所有早于给定时间戳的快照retainLast(int numSnapshots)保留当前快照最近的前 N 个祖先即使它们早于过期时间戳也不会被过期不会阻止按 ID 显式指定的快照过期deleteWith(ConsumerString deleteFunc)指定替代的删除实现例如把待删文件收集起来而不实际删除executeDeleteWith(ExecutorService)用自定义线程池并行执行文件删除planWith(ExecutorService)用自定义线程池执行过期计划planning阶段cleanExpiredFiles(boolean clean)置为false时仅过期快照、不清理底层 manifest 与数据文件适合把文件删除交给分布式框架的场景从源码看该 API 提交后会把变更应用到最新表元数据上并在发生提交冲突时自动重新应用并重试见 ExpireSnapshots.java 的类注释核心测试用例可参考 TestRemoveSnapshots.java 中对expireOlderThan、retainLast与deleteWith的组合验证。对于大表还有 Spark 版本的 Action 可以并行执行快照过期Table table ...; SparkActions .get() .expireSnapshots(table) .expireOlderThan(tsToExpire) .execute();从 ExpireSnapshotsSparkAction.java 的实现看Spark 版本先提交快照过期再通过 metadata 表反连接anti-join找出过期前后 manifest 与数据文件集合的差异来安全删除该操作涉及 shuffle并行度可通过spark.sql.shuffle.partitions控制。Spark Action 还额外支持retainLast(int)与stream-results等选项。重要过期快照会将其从元数据中移除因此它们将不再可用于时间旅行查询。注意只有当数据文件不再被任何可能用于时间旅行或回滚的快照引用时才会真正被删除。定期过期快照才能释放未使用的数据文件。清理旧元数据文件Iceberg 使用 JSON 文件跟踪表元数据。表的每次变更都会产生一个新的元数据文件以保证原子性。默认情况下旧元数据文件会保留用于历史追溯。对于提交频繁的表例如流式作业写入的表需要定期清理元数据文件。在表属性中设置write.metadata.delete-after-commit.enabledtrue即可在每次提交后自动清理。该配置会保留一部分元数据文件数量由write.metadata.previous-versions-max控制并在每次新元数据文件生成后删除最旧的。属性描述write.metadata.delete-after-commit.enabled是否在每次表提交后删除旧的被跟踪tracked元数据文件write.metadata.previous-versions-max保留的旧元数据文件数量从 TableProperties.java 可以看到这两个属性的默认值write.metadata.previous-versions-max默认为100write.metadata.delete-after-commit.enabled默认为false即默认不自动删除。更完整的属性表见 configuration.md。理解被跟踪的含义上述自动清理只删除 metadata log 中被跟踪的文件不会删除孤儿元数据文件。例如配置write.metadata.delete-after-commit.enabledfalse、write.metadata.previous-versions-max10时提交 100 次后会有 10 个被跟踪的元数据文件外加 90 个孤儿元数据文件。配置write.metadata.delete-after-commit.enabledtrue、write.metadata.previous-versions-max20时并不会立即触发自动删除而是当被跟踪文件数量再次达到write.metadata.previous-versions-max20时才会开始删除最旧的被跟踪元数据文件。底层实现上TableMetadata.addPreviousFile 会在每次提交时把旧元数据文件追加进 metadata log并按write.metadata.previous-versions-max截断超出的条目而 BaseMetastoreTableOperations.deleteRemovedMetadataFiles 在delete-after-commit.enabledtrue时会对比提交前后的previousFiles集合将不再被跟踪的元数据文件通过io().deleteFile(...)删除删除失败仅记录警告不重试、不中断提交。Hadoop 实现 HadoopTableOperations.java 中也有相同的逻辑。删除孤儿文件Delete Orphan Files在 Spark 及其他分布式处理引擎中任务或作业失败可能留下不被表元数据引用的文件某些场景下正常的快照过期也无法判定一个文件是否不再需要并删除它。清理表目录下这些孤儿文件使用deleteOrphanFilesActionTable table ...; SparkActions .get() .deleteOrphanFiles(table) .execute();DeleteOrphanFiles接口 提供了丰富的配置项方法作用location(String location)指定扫描孤儿文件的目录不设置时扫描表根目录同时覆盖数据与元数据文件olderThan(long olderThanTimestamp)只删除早于给定时间戳的孤儿文件防止误删正在写入的文件默认 3 天前deleteWith(ConsumerString deleteFunc)自定义删除实现例如只收集孤儿文件路径而不实际删除executeDeleteWith(ExecutorService)自定义删除用的线程池prefixMismatchMode(PrefixMismatchMode)处理 scheme/authority 前缀不匹配的策略取值ERROR默认抛异常、IGNORE跳过、DELETE视为孤儿删除必须极度谨慎equalSchemes(Map)/equalAuthorities(Map)声明等价 scheme / authority例如Map(s3a,s3,s3n, s3)用于消解前缀冲突危险如果保留间隔retention interval短于任何一次写入可能完成的时间删除孤儿文件可能损坏表——正在进行的写入文件会被误判为孤儿而删除。默认间隔为 3 天这一默认值同样体现在 Spark 实现 DeleteOrphanFilesSparkAction.java 的olderThanTimestamp System.currentTimeMillis() - TimeUnit.DAYS.toMillis(3)中。严重警告Iceberg 使用路径的字符串表示来判断需要删除哪些文件。在某些文件系统上同一文件的路径会随时间变化例如更换 HDFS 集群的 authority 后创建文件时的旧路径 URL 与当前目录列表中的路径不再匹配这会导致removeOrphanFiles运行时误删数据。请务必确保 metadata 表MetadataTables中的条目与 Hadoop FileSystem API 列出的条目一致以避免意外删除。该操作需要列出底层存储的全部文件来构建实际文件集合因此当数据与元数据目录中文件很多时会很耗时。建议周期性执行但无需过于频繁。从 DeleteOrphanFiles.java 的注释可以确认文件只要不被任何有效快照可达即视为孤儿而列出底层存储正是该操作开销大的原因。另外注意Spark 实现以及ExpireSnapshotsSparkAction会校验表属性gc.enabled默认true见 TableProperties.java若被显式关闭则会拒绝执行删除类操作以免损坏共享存储上的其他表。可选维护有些表需要额外维护。例如流式查询可能产生很多小数据文件需要压缩成更大的文件有些表则可以从重写 manifest 文件中获益让查询定位数据更快。压缩数据文件Compact Data FilesIceberg 会跟踪表中的每个数据文件。数据文件越多manifest 文件里存储的元数据就越多小数据文件还会因文件打开开销导致查询效率下降。Iceberg 可以通过 Spark 的rewriteDataFilesAction 并行压缩数据文件将小文件合并成大文件从而降低元数据开销与运行时文件打开成本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接口 支持的常用选项选项默认值作用target-file-size-bytes表属性write.target-file-size-bytes默认 512 MB见 TableProperties.java 与 configuration.md重写产出的目标文件大小max-file-group-size-bytes100 GB单个文件组file group允许合并的最大数据量用于拆分超大分区max-concurrent-file-group-rewrites5同时重写的文件组数量partial-progress.enabledfalse是否允许在全部重写完成前分批提交会产生多个 commitpartial-progress.max-commits10启用 partial progress 时最多允许产生的提交数partial-progress.max-failed-commits全部允许失败启用 partial progress 时最多允许失败的提交数rewrite-job-ordernone重写作业顺序bytes-asc/bytes-desc按字节、files-asc/files-desc按文件数、none按计划顺序output-spec-id当前表分区规范重写输出使用的分区规范 IDuse-starting-sequence-numbertrue新数据文件使用压缩开始时快照的序列号避免与新增 equality delete 的提交冲突重写策略同样可配置binPack()默认见 RewriteDataFilesSparkAction.execute未指定策略时自动使用 BinPack、sort()按表 SortOrder 排序重写、sort(SortOrder)指定排序、zOrder(String... columns)按指定列 Z-order 重写三种策略只能选择其一。filter(Expression)用于限定参与重写的分区或文件。如何判断哪些分区需要压缩files元数据表非常适合检查数据文件大小并决定何时压缩分区。在 Spark 中可通过SELECT * FROM prod.db.table.files查询元数据表用法见 spark-queries.md按分区汇总file_size_in_bytes即可发现文件数量多且单体偏小的分区。重写 ManifestRewrite ManifestsIceberg 利用 manifest list 与 manifest 文件中的元数据加速查询规划query planning并剪除不必要的数据文件——元数据树本质上充当了表数据的索引。manifest 在元数据树中按添加顺序自动压缩当写入模式与读取过滤条件一致时查询会更快。例如按小时分区写入的数据随时间到达天然与时间范围查询过滤条件对齐。而当表的写入模式与查询模式不一致时可以通过rewriteManifests或rewriteManifestsActionSpark 并行版本重写元数据把数据文件重新分组到 manifest 中。下面这个例子重写小 manifest并按第一个分区字段对数据文件分组Table table ...; SparkActions .get() .rewriteManifests(table) .rewriteIf(file - file.length() 10 * 1024 * 1024) // 10 MB .execute();RewriteManifests接口 还提供clusterBy(FunctionDataFile, Object func)按自定义聚类函数决定数据文件归属哪个 manifest相同 cluster key 的数据文件写入同一 manifestrewriteIf(PredicateManifestFile predicate)仅重写满足谓词的 manifest不满足的保持原样不调用时默认重写全部 manifestdeleteManifest(ManifestFile)/addManifest(ManifestFile)直接替换指定 manifest二者在重写过程中会被忽略被替换的 manifest 中活跃文件集合必须与新 manifest 一致。Spark 实现 RewriteManifestsSparkAction.java 会分别对 data manifest 与 deletes manifest 执行重写specId(int)可指定目标分区规范stagingLocation(String)可指定暂存目录同时它要求表当前必须有快照才执行。核心rewriteManifests的提交冲突处理与 commit 重试机制可参见 RewriteManifests.java 的类注释测试用例见 TestCommitReporting.java 与 TestManifestWriter.java。维护操作安全边界小结操作入口危险点过期快照table.expireSnapshots()/SparkActions.get().expireSnapshots(table)过期后快照不再可用于时间旅行与回滚清理元数据表属性write.metadata.delete-after-commit.enabled只清理被跟踪文件孤儿元数据需用deleteOrphanFiles删除孤儿文件SparkActions.get().deleteOrphanFiles(table)保留间隔不可短于写入完成时间默认 3 天HDFS 换 authority 会导致路径不匹配而误删压缩数据文件SparkActions.get().rewriteDataFiles(table)用filter限定范围、target-file-size-bytes控制目标大小重写 manifesttable.rewriteManifests()/SparkActions.get().rewriteManifests(table)替换 manifest 时活跃文件集合必须一致通用原则维护操作应周期性执行而非一次到位涉及删除的操作快照过期、孤儿文件删除建议先在测试表上用deleteWith收集待删文件清单核对无误后再执行真实删除生产环境务必确认 metadata 表条目与底层文件系统列出的路径完全一致。赞分享数据湖湖仓一体大数据【免费下载链接】icebergApache Iceberg项目地址https://gitcode.com/gh_mirrors/iceberg5/iceberg点击查看免费下载相关推荐Apache Iceberg Spark 存储过程Procedures完全指南快照管理、数据维护与表迁移实战Apache Iceberg Spark 存储过程Procedures完全指南快照管理、数据维护与表迁移实战 Apache Iceberg 为 Spark数据湖大数据数据存储Apache Iceberg表维护终极指南7个快照清理与文件优化技巧在大数据时代 Apache Iceberg 作为开源的大数据表格式正在彻底改变数据湖的管理方式。但你知道吗如果不进行定期维护Iceberg表的性能会随着数据湖大数据数据存储draw.io 桌面版安装教程3 步装好离线绘图工具覆盖 Windows / macOS / Linuxdraw.io 桌面版安装教程3 步装好离线绘图工具覆盖 Windows / macOS / Linux draw.io Desktop 是基于 Elect桌面应用图形学上一篇终极指南如何用Mechvibes让普通键盘秒变机械键盘音效神器下一篇LSPatch终极指南如何在Android 9设备上无需Root权限使用Xposed模块创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考