1. Compaction概述
1.1 什么是数据湖仓Compaction
先说说我个人的理解。Compaction,中文常翻译为「合并」或「压实」,在数据湖仓里,它干的事其实很简单——把一堆小文件合并成大文件,同时清理掉那些无用的中间数据。
你想想看,数据湖仓底层通常用 Parquet、ORC 这类列式存储格式。每次写入,哪怕只写一条数据,都可能生成一个新文件。日积月累,小文件数量会膨胀到几十万甚至上百万。Compaction 就是专门来收拾这个烂摊子的。
我记得刚接触 Iceberg 时,有个同事问我:「这不就是 Hive 里的合并小文件吗?」嗯,有点像,但又不完全一样。传统 Hive 的合并是离线跑个脚本,而湖仓的 Compaction 是框架自带的、可配置的、增量执行的机制。它更像一个后台管家,默默地把碎片整理好。
1.2 为什么需要Compaction
说白了,不搞 Compaction,你的湖仓会越跑越慢,存储成本越来越高。我在项目中遇到过几次血泪教训,这里给你列几个核心原因。
- 小文件爆炸:流式写入、CDC 同步、频繁的 INSERT INTO……这些操作都会产生大量小文件。HDFS 或对象存储对小文件并不友好,NameNode 压力大,读取时也要频繁打开关闭文件。
- 查询性能下降:一个查询要扫描上千个小文件,光是元数据开销就够受的。Parquet 的列式裁剪、谓词下推在小文件面前基本失效。
- 存储浪费:每个文件都有元数据块(footer、magic number),小文件多了,这部分冗余占比很高。我见过一个极端案例,小文件占用的存储空间比实际数据多了 30%。
- 快照膨胀:Iceberg、Hudi 这类湖仓格式每次写入都会生成新快照。如果不合并清理,快照列表会越来越长,时间旅行查询也会变慢。
1.3 Compaction的核心目标
Compaction 不是万能的,但它有几个明确的目标。我习惯把它们分成三个层次。
| 目标层次 | 具体内容 | 衡量指标 |
|---|---|---|
| 存储优化 | 合并小文件,减少文件数量;清理过期快照和孤儿文件 | 文件总数下降率、存储节省比例 |
| 性能提升 | 减少查询时扫描的文件数;提高列式存储的压缩率和索引效率 | 查询延迟、扫描文件数、IO 吞吐量 |
| 数据一致性 | 保证合并过程中数据不丢失、不重复;支持并发读写 | ACID 合规性、写入冲突率 |
嗯,这里要注意一点。很多人以为 Compaction 只是「把小文件变大」,其实它还有一个隐藏目标——清理垃圾。比如 Iceberg 里的过期快照、Hudi 里的旧版本数据,这些如果不清理,湖仓会越来越臃肿。
1.4 Compaction面临的核心挑战
Compaction 听起来简单,做起来坑不少。我踩过几次,给你总结一下。
- 资源消耗:Compaction 本质上是重写数据文件,需要大量 CPU 和 IO。如果和查询高峰期重叠,很容易把集群打满。我曾经在凌晨跑 Compaction,结果把 YARN 队列占满了,白天的报表任务全堵了。
- 并发冲突:湖仓支持并发写入,Compaction 在合并时可能和新的写入冲突。Iceberg 用乐观锁解决,Hudi 用时间线机制,但冲突处理不好会导致 Compaction 失败重试。
- 策略选择:到底合并到多大?多久合并一次?按分区合并还是全局合并?这些参数调不好,要么合并太频繁浪费资源,要么合并太少效果不明显。
- 数据一致性:合并过程中如果任务失败,不能留下脏数据。湖仓格式虽然提供了快照隔离,但实现细节上稍有不慎就会出问题。
1.5 Compaction在湖仓架构中的位置
为了让你更直观地理解,我画了一张图。这张图展示了 Compaction 在整个数据湖仓写入-读取流程中的位置。
从这张图你能看到,Compaction 处于写入和读取之间。它不直接参与数据生产,也不直接服务查询,但它是整个湖仓性能的「隐形支柱」。没有它,写入端的小文件会压垮读取端。
1.6 主流湖仓格式的Compaction实现
目前主流的湖仓格式——Iceberg、Hudi、Delta Lake——都实现了 Compaction,但思路略有不同。我简单对比一下。
| 湖仓格式 | 触发方式 | 合并策略 | 并发控制 |
|---|---|---|---|
| Apache Iceberg | 手动触发 / 定时任务 | 按分区合并,支持 rewriteDataFiles API | 乐观锁,基于快照隔离 |
| Apache Hudi | 自动内联 / 异步 | 按文件组合并,支持 Clustering 和 Cleaning | 基于时间线,写时复制或读时合并 |
| Delta Lake | 手动触发 / OPTIMIZE 命令 | 按分区或文件大小合并 | 基于事务日志,支持并发写入 |
我个人习惯用 Iceberg,因为它的快照隔离机制比较干净,Compaction 失败后回滚也很方便。但 Hudi 的自动内联 Compaction 对实时场景更友好,省去了额外调度。Delta Lake 的 OPTIMIZE 命令最简单,适合 Spark 生态的团队。
1.7 本章小结
Compaction 是数据湖仓的「清道夫」和「整理师」。它把小文件合并成大文件,清理过期数据,优化存储布局。没有它,湖仓的性能和成本都会失控。
核心挑战在于资源消耗、并发冲突和策略选择。这些坑我在项目里都踩过,后面会一一给你拆解。
嗯,这一章就到这里。记住一句话:Compaction 不是锦上添花,而是湖仓的刚需。