Iceberg 小文件治理:从快照到 Compaction
从文件、Manifest、快照三个层面建立 Iceberg 小文件治理方案,说明何时 Compaction、何时清理快照,以及如何避免误删和并发冲突。
Iceberg 小文件治理不能只做一次 Compaction。更完整的做法是同时观察数据文件、Manifest 文件和快照生命周期:先确认小文件是否已经让扫描计划变慢,再按分区和文件大小重写数据文件;随后重写过度膨胀的 Manifest;最后按回滚、时间旅行和流式读取需求过期旧快照,并清理确认不再被引用的孤儿文件。Compaction 解决的是文件布局,快照过期解决的是历史引用,二者顺序和保留策略不同,混在一起执行容易误删或反复放大元数据。
先分清三类“小”
第一类是数据文件小。流式写入、频繁提交、任务并行度过高或单批数据量不足,都会产生大量低于目标大小的数据文件。查询虽然只需要读一段时间,却仍要打开很多文件,调度、对象存储请求和文件级元数据解析成本会上升。文件太小还会让单个任务处理的数据不足,形成“读取和启动比计算更贵”的长尾。
第二类是 Manifest 小而多。Manifest 记录数据文件及其分区信息、列统计;Manifest list 记录一个快照包含哪些 Manifest,并保存部分范围信息。查询规划会先根据 Manifest list 过滤,再读取需要的 Manifest。如果每次提交都产生一批很小的 Manifest,数据文件本身不一定严重,但扫描规划仍可能变慢。
第三类是快照多。每次写入、删除、覆盖或 Compaction 都可能创建新快照。快照提供时间旅行和回滚能力,但旧快照持续保留会使旧数据文件、Manifest 和 Manifest list 继续处于引用链上。此时直接删除对象存储中的“看起来没用的文件”是不安全的,因为它可能仍被某个历史快照引用。
用指标决定是否重写
治理的第一步不是设置一个固定的文件大小阈值,而是建立基线。按表和分区记录数据文件数、文件大小分位数、最近提交频率、快照数量、Manifest 数量、查询计划时间和实际扫描文件数。把这些指标放在一起看:如果平均文件较小但查询只访问少量文件,立即 Compaction 可能收益有限;如果查询计划时间持续增长、单个分区文件数暴涨,才说明布局已经成为瓶颈。
以事件表为例,假设每天有持续写入,白天产生大量几十 MB 文件,夜间批处理形成较大文件。可以把“最近一天文件数超过基线且小文件比例上升”作为触发条件,同时限制每天重写的字节数。Apache Iceberg 的维护示例展示了按文件长度过滤并进行 bin-pack 重写,也提供了目标文件大小、最小文件大小、每次重写字节上限和并行度等控制项。这些参数是执行边界,不是所有表的通用最佳值;最终应由对象存储、查询引擎和分区数据分布的实测结果确定。
大数据基础平台 EasyMR
统一存储、计算与运维,支撑批、流、OLAP 与湖仓一体的国产化大数据底座平台
Compaction 的实施顺序
第一步,选择有限范围。优先处理查询最频繁、文件增长最快的分区,不要一上来重写整张历史表。按分区处理便于估算资源、观察查询收益,也便于在失败后只重试一个范围。
第二步,先规划再提交。重写动作会读取一组旧文件,写出新的合并文件,并在表元数据中提交替换关系。应检查待重写文件是否跨越过多分区,是否包含删除文件,以及是否有正在运行的写入任务。对于带位置删除或等值删除的表,不能把“数据文件合并”理解成删除文件也自动完成;不同动作的处理范围不同,必须确认执行引擎的实现。
第三步,控制并发。Iceberg 的提交会校验重写时的假设,例如参与重写的旧文件仍然存在、没有被另一个提交替换。如果并发写入改变了这组文件,提交可能冲突失败。合理做法是限制 Compaction 并行度和每次最大重写字节数,避开高峰写入;失败后重新规划当前快照,而不是重复提交旧计划。
第四步,验证收益。比较重写前后的文件数量、大小分布、Manifest 数量和代表性查询计划。只看到文件变大还不够,如果查询谓词与分区无关、数据本身分布很散,Compaction 可能减少文件数却没有明显减少扫描量。对实时表还要观察写入延迟,因为过大的重写任务会与正常写入争抢计算、网络和对象存储带宽。
Manifest 与快照清理不是一回事
当数据文件规模已经合理,但查询规划仍需处理大量 Manifest 时,可以执行 Manifest 重写。它主要改善元数据文件的组织,不等于重新编码所有数据。对于频繁小批提交的表,Manifest 重写往往应当独立调度,并设置更低的资源上限,避免与数据文件 Compaction 同时把读写压力推高。
快照过期则需要回答三个问题:业务需要回溯多久,流式读取器最慢多久追上,故障恢复依赖多少个历史快照。可以用“时间上限 + 至少保留最近若干个快照”的双重条件,避免短时间内连续失败导致没有可回滚点。Apache Iceberg 的快照过期操作会移除不再需要的历史快照及其关联文件;如果启用清理不再引用的元数据,还要先确认没有外部流程依赖旧 Schema 或旧分区规格。
示意流程如下:先列出当前快照和引用关系,再执行数据文件重写,验证新快照可读;等待观察窗口结束后过期旧快照;最后删除满足最小年龄条件且不再被任何有效快照引用的孤儿文件。孤儿文件清理必须设置足够的最小年龄,因为作业可能已经写完对象但尚未完成元数据提交,过早清理会删除即将被引用的文件。
数据治理
统一标准、质量、安全与资产管理,沉淀高质量数据集,支撑经营决策、监管合规与 AI 应用。
一个可落地的治理规则
可以把表分成三类。热表按小时或更短周期检测文件数和小文件比例,Compaction 只覆盖最近活跃分区;温表按天维护,并把 Manifest 重写与快照清理分开;冷表减少写入后,重点变成快照保留和孤儿文件清理。每次维护都记录输入快照、输出快照、重写字节、删除文件数、提交耗时和冲突次数,形成可追溯的运维记录。
不要用“文件越大越好”作为目标。文件过大可能降低并行度,查询只读取少量列或少量范围时也可能造成额外读取;时间分区过细会制造更多目录和文件,分区过粗则可能失去裁剪收益。真正的目标是让文件大小、分区粒度、提交频率和查询谓词相互匹配。
常见失败模式
一种失败是只做 Compaction,不过期快照,结果当前文件数下降了,存储和元数据仍继续增长。另一种是先过期快照,再发现历史查询和回滚不满足要求;因此保留策略必须由恢复目标确定。还有一种是并发冲突后直接重复旧计划,导致同一批文件反复读写;正确方式是从最新快照重新规划。
最后,治理完成的判据应是“查询和运维都得到改善”:代表性查询的规划与扫描开销下降,快照数量受控,维护任务不会挤压正常写入,失败时仍有明确的回滚点。把这些结果作为周期性检查,而不是把一次成功的 Compaction 当作终点。


