2. 核心架构对比:Iceberg的开放架构 vs Delta Lake的Spark原生架构

聊到选型,架构差异是绕不开的核心。说白了,Iceberg 和 Delta Lake 虽然都叫「湖仓一体」,但它们的基因完全不同。一个追求开放,一个拥抱原生。我当年在项目中切换过两次存储引擎,对这点感触特别深。

2.1 两种架构的设计哲学

先看一张整体对比图,帮你建立直观印象:

Iceberg vs Delta Lake 核心架构对比 Iceberg:开放架构 表格式规范(开源标准) 多引擎原生支持(Spark / Flink / Trino / Hive) REST Catalog + 文件级元数据 ACID 通过 Manifest 清单实现 Delta Lake:Spark 原生架构 Spark 插件 + Transaction Log 强依赖 Spark 运行时 Delta Log(JSON + Checkpoint) ACID 通过 Log 原子提交实现 💡 核心差异: Iceberg 定义的是「表格式规范」,任何引擎只要实现该规范就能读写;Delta Lake 是 Spark 的「存储插件」, 非 Spark 引擎需要通过 Delta Connector 桥接,性能和语义一致性会打折扣。

2.2 Iceberg:表格式规范先行

Iceberg 的核心思路很纯粹——它定义了一套开放的表格式规范。任何计算引擎,只要按照这个规范去读写数据文件,就能获得 ACID 事务和快照隔离能力。

我个人习惯把 Iceberg 比作「数据文件的 SQL 标准」。你想想看,只要你的引擎实现了 JDBC,就能连任何数据库。Iceberg 也是这个逻辑。

Iceberg 架构三要素:

  • Catalog:元数据服务层,记录当前最新快照指针。支持 Hive Metastore、REST Catalog、JDBC 等。
  • Metadata Layer:包含 Metadata File、Manifest List、Manifest File,形成树状结构。
  • Data Layer:实际数据文件,支持 Parquet、ORC、Avro 等格式。

我在项目中遇到过一个问题:团队同时用 Spark 做批处理、Flink 做实时写入、Trino 做 Ad-hoc 查询。如果用 Delta Lake,Flink 写入的数据 Trino 读不到——因为 Trino 的 Delta Connector 版本滞后。换成 Iceberg 后,三个引擎直接读写同一张表,零适配成本。

避坑指南: 我曾经以为 Iceberg 的 REST Catalog 只是「可选组件」,结果在生产环境用 Hive Metastore 做 Catalog,遇到并发写入时元数据锁冲突严重。后来切到 REST Catalog + 独立元数据服务,问题才解决。建议你从一开始就规划好 Catalog 选型。

2.3 Delta Lake:Spark 原生的存储插件

Delta Lake 的出身决定了它的架构方向——它是 Databricks 为 Spark 量身打造的存储层。核心组件是 Transaction Log(也叫 Delta Log),以 JSON 文件形式记录每次事务变更。

Delta Lake 的架构可以概括为三层:

层级 组件 说明
应用层 Spark DataFrame / SQL 用户直接操作的 API
存储层 Delta Log + Checkpoint 记录事务、版本、Schema 变更
文件层 Parquet 数据文件 实际数据存储

Delta Lake 的 ACID 实现依赖 Spark 的 文件原子性 rename 操作。每次提交事务时,Spark 会原子性地写入一个新的 Delta Log 条目。如果写入失败,整个事务回滚。

注意: Delta Lake 的 Transaction Log 默认存储在文件系统(HDFS / S3)上。这意味着每次事务提交都需要一次文件 rename 操作。在对象存储(如 S3)上,rename 不是原子操作,需要额外配置 DynamoDB 并发锁。我踩过这个坑——S3 上并发写入时出现「幻读」现象,排查了两天才发现是 rename 非原子导致的。

2.4 关键差异对比表

对比维度 Iceberg Delta Lake
架构本质 开放表格式规范 Spark 存储插件
引擎依赖 无强依赖,多引擎原生 强依赖 Spark 运行时
元数据存储 Catalog + Manifest 文件 Delta Log(JSON + Checkpoint)
ACID 实现 Manifest 原子替换 + 乐观锁 Log 原子提交 + 文件 rename
Schema 演进 列级演进,无重写 列级演进,无重写
分区演进 支持隐藏分区变更 不支持,需重写表
时间旅行 基于快照 ID 或时间戳 基于版本号或时间戳
并发控制 乐观并发 + 重试机制 乐观并发 + 文件锁

2.5 选型建议:什么场景选谁?

嗯,这里要注意,没有银弹。我根据实际项目经验总结了几条原则:

  • 多引擎混用场景 → Iceberg:如果你的团队同时用 Spark、Flink、Trino、Presto,Iceberg 是唯一能「零适配」的方案。
  • 纯 Spark 生态 → Delta Lake:如果整个技术栈都是 Spark,Delta Lake 的集成度更高,性能优化更深入。
  • 云原生对象存储 → Iceberg:Iceberg 的 Manifest 设计对 S3、OSS 更友好,没有 rename 原子性问题。
  • 需要隐藏分区变更 → Iceberg:Delta Lake 不支持分区演进,一旦分区策略变了,必须重写整张表。

我的个人建议: 如果你在建设新的数据湖平台,优先考虑 Iceberg。开放架构带来的灵活性,远大于「Spark 原生」带来的性能优势。尤其是未来可能引入 Flink、Presto 等引擎时,Iceberg 的兼容性会让你少踩很多坑。

2.6 一个真实的迁移案例

最后分享一个我经手的案例。某电商平台的数据湖最初用 Delta Lake,所有任务跑在 Spark 上。后来业务需要引入 Flink 做实时写入,问题来了:

  1. Flink 写入 Delta Lake 需要 Delta Connector,版本必须和 Spark 集群对齐。
  2. Trino 查询 Delta Lake 时,部分复杂类型(如 Map、Array)解析出错。
  3. 并发写入时,S3 上的 rename 操作导致数据不一致。

我们花了三周时间迁移到 Iceberg。迁移后,Flink 直接写入 Iceberg 表,Trino 直接查询,Spark 继续做批处理。三个引擎读写同一张表,零冲突。嗯,这个案例让我彻底成了 Iceberg 的拥趸。