数据湖表格式三剑客:Hudi vs Iceberg vs Paimon 深度解析与选型指南

一、引言

随着实时数仓架构从 Lambda 向 Lakehouse 演进,数据湖表格式(Table Format)成为架构选型的核心决策点。Apache Hudi、Apache Iceberg 和 Apache Paimon 是当前最主流的三个开源方案,它们各自从不同的业务场景出发,在 ACID 事务、增量处理、流批一体等维度形成了差异化的技术路线。

本文将从架构设计、核心机制、适用场景三个层面进行深入对比,并结合实时工程实践给出选型建议。

二、Apache Hudi 架构

Hudi 的核心设计围绕Timeline(时间线)和Index(索引)两大机制展开。

复制代码
┌──────────────────────────────────────────────────────────┐
│                    Hudi 表架构                            │
├──────────────────────────────────────────────────────────┤
│                                                          │
│  ┌─────────────────────────────────────────────────┐     │
│  │              Timeline (元数据时间线)              │     │
│  │  [commit1] -> [commit2] -> [deltacommit3] -> ...│     │
│  └─────────────────────────────────────────────────┘     │
│                         │                                │
│           ┌─────────────┼─────────────┐                  │
│           ▼             ▼             ▼                  │
│  ┌──────────────┐ ┌──────────────┐ ┌──────────────┐     │
│  │  File Group  │ │  File Group  │ │  File Group  │     │
│  │ ┌──────────┐ │ │ ┌──────────┐ │ │ ┌──────────┐ │     │
│  │ │Base File │ │ │ │Base File │ │ │ │Base File │ │     │
│  │ │(Parquet) │ │ │ │(Parquet) │ │ │ │(Parquet) │ │     │
│  │ ├──────────┤ │ │ ├──────────┤ │ │ └──────────┘ │     │
│  │ │Log File 1│ │ │ │Log File 1│ │ │   (COW表)    │     │
│  │ │Log File 2│ │ │ └──────────┘ │ │              │     │
│  │ └──────────┘ │ │   (MOR表)    │ │              │     │
│  │   (MOR表)    │ │              │ │              │     │
│  └──────────────┘ └──────────────┘ └──────────────┘     │
│                                                          │
│  ┌─────────────────────────────────────────────────┐     │
│  │              Index (记录到文件的映射)             │     │
│  │  Record Key -> File Group ID                    │     │
│  │  类型: Bloom / Simple / HBase / Bucket          │     │
│  └─────────────────────────────────────────────────┘     │
│                                                          │
└──────────────────────────────────────────────────────────┘

Timeline 机制:每次写入操作(commit/deltacommit/compaction/clean 等)在 Timeline 上记录一个 instant,包含时间戳 + 动作类型 + 状态(requested/inflight/completed),这是 Hudi 实现 ACID 和增量查询的基础。

索引机制:Hudi 通过索引将 Record Key 映射到 File Group,实现高效 Upsert。

  • Bloom Filter Index:默认索引,基于文件级别 Bloom Filter,适合大数据量场景。
  • Bucket Index:基于 Hash 分桶,确定性路由,Flink 写入推荐使用。
  • Record-level Index:基于 HFile 的全局索引,提升 Upsert 效率。

|------|---------------------|---------------------|
| | Copy-on-Write (COW) | Merge-on-Read (MOR) |
| 写入方式 | 每次写入重写整个文件 | 追加写入 Log 文件 |
| 读取性能 | 高(直接读 Parquet) | 需合并 Base + Log |
| 写入延迟 | 较高 | 较低 |
| 适用场景 | 读多写少 | 写多读少、近实时场景 |

三、Apache Iceberg 架构

Iceberg 的核心设计围绕三层元数据树展开,实现了计算引擎与存储的完全解耦。

复制代码
┌──────────────────────────────────────────────────────────┐
│                 Iceberg 元数据架构                        │
├──────────────────────────────────────────────────────────┤
│                                                          │
│  ┌────────────────────────┐                              │
│  │       Catalog          │  (记录当前 metadata 指针)     │
│  │  table -> metadata ptr │                              │
│  └───────────┬────────────┘                              │
│              │                                           │
│              ▼                                           │
│  ┌────────────────────────┐                              │
│  │   Metadata File (.json)│  (Schema/Partition/Snapshot) │
│  │  ┌──────────────────┐  │                              │
│  │  │ Snapshot List     │  │                              │
│  │  │ snap-1 -> mlist-1 │  │                              │
│  │  │ snap-2 -> mlist-2 │  │                              │
│  │  └──────────────────┘  │                              │
│  └───────────┬────────────┘                              │
│              │                                           │
│              ▼                                           │
│  ┌────────────────────────┐                              │
│  │ Manifest List (.avro)  │  (本次快照包含哪些 manifest)  │
│  │  manifest-1.avro       │                              │
│  │  manifest-2.avro       │                              │
│  └───────────┬────────────┘                              │
│              │                                           │
│              ▼                                           │
│  ┌────────────────────────┐                              │
│  │ Manifest File (.avro)  │  (数据文件列表 + 统计信息)    │
│  │  data-file-1.parquet   │                              │
│  │  data-file-2.parquet   │                              │
│  │  (含 min/max/count     │                              │
│  │   null_count 等统计)   │                              │
│  └───────────┬────────────┘                              │
│              │                                           │
│              ▼                                           │
│  ┌────────────────────────┐                              │
│  │     Data Files         │  (Parquet / ORC / Avro)      │
│  └────────────────────────┘                              │
│                                                          │
└──────────────────────────────────────────────────────────┘
  • Snapshot 隔离:每次写操作生成一个新的 Snapshot,读写互不阻塞,支持 Time Travel。
  • Hidden Partitioning:分区转换对用户透明,无需在查询中手动指定分区列。例如定义 partition by days(ts)后,查询只需 WHERE ts > '2024-01-01',Iceberg 自动完成分区裁剪。
  • Partition Evolution:可在不重写数据的情况下修改分区策略,新数据使用新分区方式,旧数据保持不变。
  • Schema Evolution:支持 Add / Drop / Rename / Reorder / Type Promotion,通过列 ID(而非列名)追踪列,保证向前兼容。

四、Apache Paimon 架构

Paimon 的核心设计基于LSM Tree存储结构,原生支持流式写入与 Changelog 生产。

复制代码
┌──────────────────────────────────────────────────────────────┐
│                     Paimon 表架构                             │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│  Table                                                       │
│  ├── Partition (可选)                                        │
│  │   ├── Bucket 0                                           │
│  │   │   └── LSM Tree                                       │
│  │   │       ├── Level 0: [sorted-run] [sorted-run]         │
│  │   │       ├── Level 1: [sorted-run]                      │
│  │   │       ├── Level 2: [sorted-run]                      │
│  │   │       └── ...                                        │
│  │   ├── Bucket 1                                           │
│  │   │   └── LSM Tree                                       │
│  │   └── ...                                                │
│  └── ...                                                     │
│                                                              │
│  ┌───────────────────────────────────────────────────┐       │
│  │              Snapshot 管理                         │       │
│  │  snapshot-1 -> manifest-list -> manifests -> files│       │
│  │  snapshot-2 -> ...                                │       │
│  └───────────────────────────────────────────────────┘       │
│                                                              │
│  ┌───────────────────────────────────────────────────┐       │
│  │           Changelog 生产                           │       │
│  │  +I / -U / +U / -D (完整 CDC 语义)                │       │
│  └───────────────────────────────────────────────────┘       │
│                                                              │
└──────────────────────────────────────────────────────────────┘
  • LSM Tree 存储:数据先写入内存(MemTable),flush 到 Level 0 形成 sorted-run,后台 Compaction 逐层合并。这种结构天然适合高频写入。
  • Merge Engine:Primary Key Table 支持多种合并策略:

|----------------|--------------------|--------|
| Merge Engine | 行为 | 适用场景 |
| deduplicate | 保留最新记录 | 去重入湖 |
| partial-update | 多流字段级合并 | 宽表拼接 |
| aggregation | 聚合计算(sum/max/min等) | 预聚合 |
| first-row | 保留首条记录 | 去重保留最早 |

  • Changelog 生产:Paimon 可在 Compaction 时生成完整的 changelog(+I/-U/+U/-D),下游 Flink 作业可直接消费,无需依赖 Kafka 作为中间层。
  • 流式读取:支持 Streaming Read,Flink 作业可持续消费表的增量变更,实现湖上流处理。

五、核心特性对比

1.特性矩阵

|---------------------|-------------------------------|---------------------------------------------|----------------------------|
| 特性维度 | Hudi | Iceberg | Paimon |
| ACID 事务 | ✅ 基于 Timeline | ✅ 基于 Snapshot | ✅ 基于 Snapshot |
| Upsert 能力 | ✅ 索引驱动,高效 | ✅ Merge-on-Read / COW | ✅ LSM Tree 原生支持 |
| 增量查询 | ✅ 增量 Pull 模型 | ✅ Incremental Scan | ✅ Streaming Read |
| Time Travel | ✅ | ✅ | ✅ |
| Schema Evolution | ✅ | ✅(最完善) | ✅ |
| Partition Evolution | ❌ | ✅(独有优势) | ❌ |
| Hidden Partitioning | ❌ | ✅ | ❌ |
| Changelog 生产 | ⚠️ CDC 格式需额外配置 | ❌ 需外部工具 | ✅ 原生支持 |
| 流式 Sink | ✅ Flink/Spark | ✅ Flink/Spark | ✅ Flink 原生最优 |
| 流式 Source | ⚠️ 支持但非核心路径 | ⚠️ 支持但有限制 | ✅ 原生 Streaming Read |
| 存储结构 | File Group (Base+Log) | 扁平数据文件 | LSM Tree |
| 小文件治理 | Clustering + Compaction | Compaction + Rewrite | Compaction(自动) |
| 引擎兼容性 | Spark/Flink/Hive/Presto/Trino | Spark/Flink/Trino/Presto/Dremio/StarRocks 等 | Flink(最佳)/Spark/Hive/Trino |

2.写入流程对比

复制代码
┌─────────────── 写入流程对比 ──────────────────────────────┐
│                                                           │
│  【Hudi COW】                                             │
│  Record → Index Lookup → 定位 File Group → 读取原文件     │
│  → 合并 → 写入新 Base File → 更新 Timeline               │
│                                                           │
│  【Hudi MOR】                                             │
│  Record → Index Lookup → 定位 File Group → 追加 Log File  │
│  → 更新 Timeline (后台异步 Compaction 合并到 Base File)    │
│                                                           │
│  【Iceberg COW】                                          │
│  Record → 写入新 Data File → 生成新 Manifest              │
│  → 生成新 Manifest List → 生成新 Snapshot → 原子提交      │
│                                                           │
│  【Iceberg MOR (v2)】                                     │
│  Delete → 写入 Delete File (position/equality)            │
│  → 读取时合并 Data File + Delete File                     │
│                                                           │
│  【Paimon Primary Key Table】                             │
│  Record → Hash 到 Bucket → 写入 MemTable                  │
│  → Flush 到 Level 0 → 后台 Compaction 合并各层            │
│  → 生成 Changelog → 更新 Snapshot                         │
│                                                           │
└───────────────────────────────────────────────────────────┘

3.读取流程对比

|---------|------------------------------|----------------------------|-----------------------------|
| | 快照读 | 增量读 | 流式读 |
| Hudi | 读取最新 commit 的文件(MOR 需 merge) | 指定 beginTime/endTime 范围 | Flink Source 持续拉取 |
| Iceberg | 读取指定 Snapshot 对应的文件 | 对比两个 Snapshot 的差异文件 | Flink Source 监控新 Snapshot |
| Paimon | 读取最新 Snapshot | 读取两个 Snapshot 间的 changelog | Flink Source 持续消费 changelog |

六、场景选型建议

复制代码
┌────────────────────────────────────────────────────────────────┐
│                   场景匹配推荐                                  │
├────────────────────────────────────────────────────────────────┤
│                                                                │
│  CDC 增量入湖 (MySQL/PG binlog → 湖)                           │
│  ├── 推荐: Hudi ★★★ (索引驱动 Upsert, 成熟的 CDC 生态)        │
│  ├── 可选: Paimon ★★☆ (LSM 天然适合高频写入)                   │
│  └── 一般: Iceberg ★★☆ (v2 支持但 Upsert 效率相对偏弱)        │
│                                                                │
│  实时流式数仓 (Flink 流处理链路)                                │
│  ├── 推荐: Paimon ★★★ (原生 Changelog, 流读写最优)            │
│  ├── 可选: Hudi ★★☆ (MOR + Flink 可用)                        │
│  └── 一般: Iceberg ★★☆ (Flink 集成持续改进中)                  │
│                                                                │
│  大规模批处理分析 (多引擎 Ad-hoc 查询)                          │
│  ├── 推荐: Iceberg ★★★ (引擎无关, 元数据管理强)               │
│  ├── 可选: Hudi ★★☆ (COW 表读取性能好)                         │
│  └── 一般: Paimon ★★☆ (非 Flink 引擎支持在追赶中)             │
│                                                                │
│  多流拼接宽表 (多数据源字段级合并)                              │
│  ├── 推荐: Paimon ★★★ (partial-update merge engine)           │
│  ├── 可选: Hudi ★★☆ (Payload 自定义合并)                       │
│  └── 一般: Iceberg ★☆☆ (需应用层处理)                          │
│                                                                │
│  数据湖上的维表 Join                                           │
│  ├── 推荐: Paimon ★★★ (原生 Lookup Join 优化)                 │
│  ├── 可选: Hudi ★★☆ (支持但配置复杂)                           │
│  └── 一般: Iceberg ★★☆ (需额外缓存机制)                       │
│                                                                │
└────────────────────────────────────────────────────────────────┘