[数据湖] Apache Iceberg : 一种面向海量分析型数据集的开放表格式
1 概述

产品介绍
- 产品定位:Apache Iceberg 是一种面向海量分析型数据集的开放表格式(Open Table Format),并非【数据库】、【查询引擎】或【存储系统】。
它在【对象存储】(S3 / GCS / ADLS / HDFS)上的
Parquet/ORC/Avro数据文件之上,叠加一层元数据与事务抽象,让原始文件拥有接近SQL表的语义(ACID、Schema 演化、隐藏分区、时间旅行)。
- 诞生背景与原因:
- 无可靠 ACID 事务、Schema 变更需重写数据、依赖目录 listing 做分区裁剪导致大规模下表规划极慢。
- Ryan Blue 与 Daniel Weeks 主导启动
Iceberg,用“文件级元数据树 + 原子提交”替代“目录即分区”的 Hive 模型。
-
解决的核心问题:
- 把仓库级可靠性(原子提交、Serializable 隔离、乐观并发)下沉到【数据湖】;
- 【查询引擎】无需 list 目录即可做文件级/列级裁剪;
- 支持Add/Drop/Rename/Reorder 列而【无需重写数据】;
- 通过 Snapshot 机制原生支持【时间旅行与回滚】;
- 成为【引擎中立】标准,Spark / Trino / Flink / Hive / Impala / Snowflake / BigQuery / DuckDB 均可读同一份表。
-
Apache Iceberg URL:
发展历程
- 2017:Netflix 内部启动,初版 Java 实现。
- 2018-11:开源并捐赠给
Apache软件基金会,进入 Incubator。 - 2020-05:毕业为 Apache Top-Level Project(TLP)。
- ~2022(V2 Spec):引入 Delete Files(position / equality delete),支持行级
UPDATE/DELETE/MERGE,脱离“【只能 append/overwrite 分区】”。 - 2025-09:1.10.0 稳定线;随后 V3 Spec 落地(Deletion Vectors、VARIANT 类型、Row Lineage、geometry/geography、timestamp_ns、默认列值等)。
- 2026-05:发布 1.11.0,完整实现
V3,Deletion Vectors 生产可用,增加服务端 Scan Planning、表级加密、Spark 4.x / Flink 2.x 支持。 - 2026 至今:V4 Spec 在邮件列表与设计文档阶段推进(single-file commit、Content Stats、relative path、列式元数据等),尚未发布可量产 spec。
核心功能
- ACID 与并发控制:每次写入产生新 Snapshot,Catalog 指针原子切换;多写者走乐观并发 + 序列号冲突重试,读者永不看到部分写入。
- 完整 Schema Evolution:基于字段 ID 追踪,支持【加列/删列/改名/调序/安全类型拓宽】,历史数据文件无需重写,不会出现“【僵尸数据】”。
- Hidden Partitioning(隐藏分区):用户按原始列写
WHERE ts > ...,Iceberg 自动应用month/day/bucket/truncate/hour等 transform 做【分区裁剪】;分区列不污染业务 Schema。 - Partition Evolution:分区策略可随负载演变(如从
day(ts)改hour(ts)),新旧布局共存,无需重写全表。 - Time Travel & Rollback:按 Snapshot ID 或时间戳读取历史一致视图;可一键回滚到良好 Snapshot。
- 行级变更:V2 起支持 position/equality delete;V3 起推荐 Deletion Vector(Puffin + Roaring Bitmap),MERGE/UPDATE/DELETE 免大规模重写。
- 数据压缩与维护:自带 rewrite_data_files(bin-pack / sort / Z-order / Hilbert 实验)、snapshot expire、orphan file clean。
- 多引擎同表:同一份 Iceberg 表可被 Spark 写、Trino 读、Flink 流灌、Snowflake 外表挂载。
主要特点
- 真正开放:Apache 2.0 协议,ASF 治理,无单一厂商绑定;spec 与实现分离(Java 参考实现 + Python/Go/Rust 实现)。
- 引擎与 Catalog 中立:Catalog 可为 Hive MetaStore / AWS Glue / JDBC / Nessie / Polaris(REST) / Hadoop 本地;引擎侧各厂商自行实现 SPI。
- 元数据树避免目录 listing:Catalog → Metadata JSON → Manifest List → Manifest → Data File,规划复杂度为【元数据跳转】而非
O(n)目录遍历。 - 列统计内嵌:Manifest 内记录 per-file min/max/null_count/bytes,支持细粒度文件裁剪。
- 存储格式解耦:数据文件可用
Parquet(主流)/ORC/Avro。
局限性
- 自身不是【查询引擎】:性能取决于 Spark/Trino 等【消费方】;小文件、过期 Snapshot、orphan file 需【主动运维】。
- 流式高频写入有 commit 放大:V3 下每次 commit 仍可能写 metadata.json + manifest list + manifest;V4 正试图用 single-file commit 缓解。
- Equality Delete 读放大历史包袱:V2 表若未 compaction,delete 文件过多会拖慢【读操作】;需依赖后台 compaction 策略。
Equality Delete(等值删除)是 Apache Iceberg Spec V2 引入的两种 Delete File 之一(另一种是 Position Delete),用来在不重写数据文件、且不知道行物理位置的前提下,实现行级 DELETE / UPDATE / MERGE。
核心思想:用“列值”而不是“文件+行号”来标记哪些行逻辑上已删除。
它解决的问题与产生背景
1 对象存储不可原地改行,V1 只能 Copy-on-Write 整文件重写;
2 CDC / Flink 流上游只给你 user_id=12345 已删除 这种业务键值,并不清楚这行在 `s3://.../part-007.parquet` 文件的第几行;
3 `Equality Delete` 让 `writer` 无需扫描【数据文件】来定位行位置,直接把 `{user_id:12345}` 写进一个小 delete 文件即可,写路径极轻。
- Catalog 选型影响事务语义:Hadoop catalog 仅靠文件 rename 提供弱原子;生产建议 REST/JDBC/Nessie/Glue 等强一致型的 catalog。
- 跨引擎能力不对齐:V3 特性(Deletion Vector / Variant)在 Spark 支持好,Trino/DuckDB 等滞后,【混用引擎】需注意
feature matrix。

适用场景
- 基于 S3/OSS/COS 构建开放 Lakehouse,拒绝数仓锁定、被厂商锁定。
- 多引擎共治:Spark 批处理 + Flink 流注入 + Trino/Dremio 交互式 BI + Python(
PyIceberg) 直接分析。 - 需要时间旅行、审计、回滚、CDC 入湖的金融/电商/日志平台。
- 宽表 Schema 频繁演进(埋点、特征表、LLM embedding 表)。
- 【多云/混合云】下共享同一逻辑表给不同团队。
同类竞品
- Delta Lake:Databricks 系出身,Spark 深度集成,UniForm 桥接 Iceberg;Iceberg 在“多引擎中立 + Catalog 多样”上更彻底。
- Apache Hudi:Uber 开源,擅长流式 CDC / MOR 表 / 索引,对近实时 upsert 场景成熟;Iceberg 在开放生态与 BI 引擎覆盖面更广。
- Paimon(原 Flink Table Store):面向 Flink 流批一体,主键表 LSM 结构;与 Iceberg 定位部分重叠但内核不同。
- 商业 Warehouse 外表:Snowflake Iceberg Table / BigQuery Iceberg / Databricks Iceberg v3 —— 它们消费 Iceberg,而不是替代 Iceberg。
发展趋势
-
社区活跃度:Dev 邮件列表、GitHub PR、Rust/Python/REST Catalog/Terraform Provider 多语言生态同步迭代;2026 年焦点在 V4 元数据降本(single-file commit、Content Stats、relative path)。
-
Star / Fork 趋势:GitHub 长期位居数据湖格式榜首,2026 年周新增 Star 维持高位(外部观测约 9k+ 区间波动),Fork 与 contributor 数持续增长,Netflix/Apple/Airbnb/Snowflake/Databricks 均有人参与 spec 讨论。
-
总结:Iceberg 已成为开放 Lakehouse 表格式的事实标准,未来 12–18 个月的主线是从“功能完备的 V3”走向“元数据更轻、提交更便宜的 V4”,并进一步【统一多引擎元数据互操作】。
2 工作原理与架构
概念术语
- Table Format:定义数据文件如何被组织成表、如何提交变更、如何做事务的规范,不等于存储格式。
- Catalog:表的“入口指针服务”,记录
tableName → 当前 metadata.json 路径;原子换指针即完成 commit。 - Metadata File(metadata/*.json):存 schema、partition specs、sort orders、snapshot 列表、当前 snapshot-id、properties。
- Snapshot:表在某次提交后的不可变一致性视图;每次写产生新 snapshot。
- Manifest List(*.avro):一个 snapshot 对应一个,列出本 snapshot 涉及的 manifest 文件及分区级摘要。
- Manifest File(*.avro):记录一组 data file 的路径、partition tuple、row count、列级 min/max/null_count、sequence number。
- Data File / Delete File:实际 Parquet/ORC/Avro 数据;V2 起 delete file 标记被删行;V3 起推荐 Deletion Vector 存于 Puffin。
- Hidden Partition Transform:
identity/month/day/hour/bucket/truncate/hour等函数,查询用原始列、物理按 transform 分区。 - Sequence Number:manifest/snapshot 单调增序号,解决多写者顺序与 delete 应用顺序。
架构与运行原理 *
- 三层逻辑架构(Catalog / Metadata / Data):
-
写路径:
- 引擎算出新数据文件 / delete 文件;
- 写新的 Manifest(含统计)→ 写 Manifest List → 写新 Metadata JSON(追加 snapshot);
- 通过 Catalog 做原子指针切换(乐观锁校验 base snapshot 未变,否则重试)。
-
读路径:
- 问 Catalog 拿 metadata.json;
- 取 current snapshot → manifest list → 并行读 manifest;
- 用 partition bound + 列 min/max 做文件裁剪,绝不扫全表目录;
- 对 V2/V3 表合并 delete file / deletion vector 得到可见行集。
-
时间旅行:
SELECT * FROM t FOR SYSTEM_VERSION AS OF 123456789或AS OF '2026-07-31 10:00:00'直接选历史 snapshot-id,复用旧 manifest 树。
关键模块(Java 参考实现)
iceberg-api:公开 API 与接口;iceberg-core:API 参考实现、Avro 支持;iceberg-parquet/iceberg-orc/iceberg-arrow:文件格式集成;iceberg-spark/iceberg-flink/iceberg-mr:引擎 Datasource V2 / Streaming / Hive InputFormat 集成;iceberg-hive-metastore:HMS Catalog 后端;- 周边:
pyiceberg(Python 原生)、iceberg-rust、iceberg-go、polaris(REST Catalog 服务端)。
Iceberg Catalog 元数据系统 *
对 iceberg-flink-quickstart Demo 中,Iceberg-Rest 容器服务(Rest Catalog)的解读 *
- docker//docker-compose.yml 中定义的
iceberg-rest容器的镜像 :apache/iceberg-rest-fixture
- 参考文献:
- docker-compose.yml
services:
...
# Iceberg REST Catalog
iceberg-rest:
image: apache/iceberg-rest-fixture
hostname: iceberg-rest
depends_on:
create-bucket:
condition: service_completed_successfully
networks:
iceberg_net:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8181/v1/config"]
interval: 5s
timeout: 3s
retries: 5
environment:
AWS_REGION: us-east-1
CATALOG_WAREHOUSE: s3://warehouse/
CATALOG_IO__IMPL: org.apache.iceberg.aws.s3.S3FileIO
CATALOG_S3_ENDPOINT: http://minio:9000
CATALOG_S3_ACCESS__KEY__ID: admin
CATALOG_S3_SECRET__ACCESS__KEY: password
...
在
iceberg-flink-quickstart这个 Demo 里,iceberg-rest容器跑的是 Apache Iceberg REST Catalog 的测试夹具(test fixture),镜像为apache/iceberg-rest-fixture。
它不是一个【生产级 Catalog】(如 Polaris/Nessie/Glue),而是Iceberg官方用来"开箱即跑、验证多引擎互通"的 REST Catalog 参考实现/适配器。
iceberge-rest-fixture镜像 (iceberg-rest容器) 是什么
-
它是 Apache Iceberg 仓库 docker/iceberg-flink-quickstart 里 docker/iceberg-rest-fixture 构建出的 REST Catalog Adapter Test Fixture——一个把"已有 Iceberg Catalog 实现"包成 WEB HTTP 服务的适配器。
-
docker-compose.yml里没设CATALOG_CATALOG__IMPL的字样,但apache/iceberg-rest-fixture镜像的 Dockerfile 里已经写死了2条 ENV:
CATALOG_CATALOG__IMPL=org.apache.iceberg.jdbc.JdbcCatalogCATALOG_URI=jdbc:sqlite::memory:(默认: 内存版SQLLite)
- 本质:Jetty/Jersey 起的 HTTP 服务 + 内部套一个 JdbcCatalog + 连 SQLite 内存库
一个 HTTP 服务,实现了 https://iceberg.apache.org/docs/latest/rest-catalog(
/v1/config、/v1/namespaces、/v1/namespaces/{ns}/tables/{table}等端点)。
- 角色:在 Flink SQL 里你配的
'catalog-impl'='org.apache.iceberg.rest.RESTCatalog' + 'uri'='http://iceberg-rest:8181',客户端就是跟它对话;它再转交给背后的【真正元数据存储】(默认内存 SQLite JdbcCatalog)。
默认服务名
rest_backend,监听 8181,/v1/config是咱们 healthcheck 里 curl 的那个端点
- 官方定位:名字带 fixture,即 "Adapter Test Fixture"——给 Spark/Flink/Trino/PyIceberg 做 REST 协议联通性测试用的【轻量Web服务端】。
起什么作用、提供什么能力
-
作用:让
Flink SQL等【上层应用程序】基于catalog-impl=org.apache.iceberg.rest.RESTCatalog走标准Iceberg REST Open API建库建表,而不用 Flink 直接依赖 Hive/JDBC 客户端。协议层解耦多引擎。 -
能力(HTTP 侧):namespace 增删查、table 注册/加载/commit(乐观锁返 409)、
/v1/config下发 warehouse 与 IO 配置。 -
docker-compose.yml里那几个 ENV 的含义**(CATALOG_前缀剥离后变成 catalog property):
CATALOG_WAREHOUSE=s3://warehouse/→ 表数据根路径CATALOG_IO__IMPL=org.apache.iceberg.aws.s3.S3FileIO→ 数据文件走 S3FileIO 写 MinIOCATALOG_S3_ENDPOINT=http://minio:9000+ ak/sk → 告诉服务端(以及通过 config 下发给客户端)对象存储怎么连
- 注意:【元数据】本身不进 S3存储,只【数据文件】进 MinIO;【元数据指针】进 SQLite。
-
解耦作用:把"【Catalog 客户端逻辑】"从各计算引擎(Flink/Spark/Trino)里抽出来,变成统一 HTTP 协议。【计算引擎侧】只需实现一次
RESTCatalogclient,不用再为每个后端(Hive/JDBC/Glue)写 connector。 -
对外提供的能力(HTTP API):
- Namespace 管理:
CREATE DATABASE→POST /v1/namespaces- Table 注册与发现:
CREATE TABLE/SHOW TABLES→POST /v1/namespaces/{ns}/tables、GET .../tables- 加载表元数据(返回 metadata.json 位置、snapshot 指针):
GET .../tables/{table}- Commit 原子更新(乐观锁:带 requirement 比对,冲突返 409):
POST .../tables/{table}/v1/config下发 warehouse、vended credential 等- 可选 OAuth token 端点(fixture 默认不强制开鉴权)
在 quickstart 里具体承载:Flink 建
iceberg_catalog.nyc.taxis→ 发 REST 请求给 8181 →iceberge-rest-fixture把库表指针存 默认的内存SQLite、把warehouse=s3://warehouse/下数据/metadata 文件交给 MinIO(S3FileIO)。
基于什么组件构建
- 服务框架:Iceberg 代码库里的
iceberg-rest-catalog/iceberg-open-api模块(shadowJar 打进镜像),底层用 Jetty(内嵌)+ JAX-RS(Jersey) 起 HTTP 服务,不是 Spring Boot,也不是 Spark。 - 默认元数据存储:未设
CATALOG_CATALOG__IMPL和CATALOG_URI时,fallback 到 内存版 SQLite 的 JdbcCatalog,DB 文件在容器 tmpfs(如/tmp/iceberg_catalog.db)。 - 可插拔后端:通过环境变量可换成 PostgreSQL/MySQL JDBC,或指定
catalog-impl(如 HiveCatalog 适配层);IO 层可配S3FileIO/HadoopFileIO。 - 镜像构建:
docker/iceberg-rest-fixture/Dockerfile,基于 Iceberg 主线 Gradle 构建的 shadow jar + 精简 JRE。
Iceberge的内存版SQLLite vs. MinIO 上 <database>/<table>/metadata/*.metadata.json 文件
- 但为什么我能在 MinIO 上看到 metadata/*.metadata.json 文件?
前面提及的元数据存储在默认的内存SQLLite中,二者到底有何区别?
如果我停止 该iceberg-flink-quickstart项目的 iceberg-rest 容器,再重新启动,Flink SQL Client上是否能正常读取到MinIO的库表定义和表数据?
- 为何 MinIO 有
metadata.json?
Iceberg 每次写入/提交都会生成表【元数据文件】(记录 schema、快照、数据文件指针等)并存入对象存储。这是 Iceberg 表格式的标准行为,与 Catalog 后端无关。
- 二者区别
- MinIO 中的
metadata.json:是表元数据(Table Metadata),记录表的具体结构、历史和文件清单。 - 内存 SQLite:是 Catalog 注册表(Registry),仅存储“库/表名 ➡️ 最新
metadata.json路径”的指针。
类比:SQLite 是“电话簿”,MinIO 文件是“具体的档案内容”。
- 重启
iceberg-rest后能否读取?
不能。 容器重启导致【内存 SQLite】 数据清空(失忆),Flink 向 Catalog 询问表位置时,会返回“表不存在”。虽然 MinIO 里的表结构和数据文件物理上还在,但因失去了 Catalog 的“入口指针”,SQL Client 无法正常加载和读取。
- 在不改变任何组件的情况下,当重启 iceberg-rest 容器后,如何主动让其读取 MinIO 上的库表定义到内存SQLLite,以解决 内存SQLLite失忆的问题?
结论:无法主动恢复。
iceberg-rest-fixture内置的JdbcCatalog不具备“扫描对象存储反推 Catalog 注册信息”的能力(即无 Hive Metastore 那种metastore.warehouse.dir扫描机制)。- 内存 SQLite 只认显式的
CREATE TABLE写入。重启后指针丢失,MinIO 上的文件对它而言只是“【孤儿文件】”。
- 唯一可行方案(不改组件):
- 因为DDL逻辑是幂等的(若
metadata.json已存在则会复用),这会重新向内存 SQLite 写入指针,从而“唤醒”原有表。- 重启 iceberg-rest 容器后,手动在 Flink SQL Client 中重新执行
CREATE CATALOG即可。
//20260731 亲测:无需再 CREATE DATABASE` 和 `CREATE TABLE`
ash-4.4# docker stop iceberg-flink-quickstart-iceberg-rest-1
iceberg-flink-quickstart-iceberg-rest-1
ash-4.4# docker start iceberg-flink-quickstart-iceberg-rest-1
iceberg-flink-quickstart-iceberg-rest-1
ash-4.4# docker exec -it jobmanager ./bin/sql-client.sh
...
______ _ _ _ _____ ____ _ _____ _ _ _ BETA
| ____| (_) | | / ____|/ __ \| | / ____| (_) | |
| |__ | |_ _ __ | | __ | (___ | | | | | | | | |_ ___ _ __ | |_
| __| | | | '_ \| |/ / \___ \| | | | | | | | | |/ _ \ '_ \| __|
| | | | | | | | < ____) | |__| | |____ | |____| | | __/ | | | |_
|_| |_|_|_| |_|_|\_\ |_____/ \___\_\______| \_____|_|_|\___|_| |_|\__|
Welcome! Enter 'HELP;' to list all available commands. 'QUIT;' to exit.
Command history file path: /opt/flink/.flink-sql-history
Flink SQL> SELECT * FROM iceberg_catalog.nyc.taxis;
[ERROR] Could not execute SQL statement. Reason:
org.apache.calcite.sql.validate.SqlValidatorException: Object 'iceberg_catalog' not found
Flink SQL> show catalogs;
+-----------------+
| catalog name |
+-----------------+
| default_catalog |
+-----------------+
1 row in set
Flink SQL> use catalog iceberg_catalog;
[ERROR] Could not execute SQL statement. Reason:
org.apache.flink.table.catalog.exceptions.CatalogException: A catalog with name [iceberg_catalog] does not exist.
Flink SQL> CREATE CATALOG iceberg_catalog WITH (
> 'type' = 'iceberg',
> 'catalog-impl' = 'org.apache.iceberg.rest.RESTCatalog',
> 'uri' = 'http://iceberg-rest:8181',
> 'warehouse' = 's3://lakehouse/icebgerg/',
> 'io-impl' = 'org.apache.iceberg.aws.s3.S3FileIO',
> 's3.endpoint' = 'http://minio:9000',
> 's3.access-key-id' = 'xxx',
> 's3.secret-access-key' = 'xxx',
> 's3.path-style-access' = 'true'
> );
[INFO] Execute statement succeeded.
Flink SQL> show catalogs;
+-----------------+
| catalog name |
+-----------------+
| default_catalog |
| iceberg_catalog |
+-----------------+
2 rows in set
Flink SQL> use catalog iceberg_catalog;
[INFO] Execute statement succeeded.
Flink SQL> show databases;
+------------------+
| database name |
+------------------+
| default_database |
| nyc |
+------------------+
2 rows in set
Flink SQL> use nyc;
[INFO] Execute statement succeeded.
Flink SQL> show tables;
+------------+
| table name |
+------------+
| taxis |
+------------+
1 row in set
Flink SQL> exit;
重申结论:不改组件无解,只能重跑 DDL。根治需换 PG 等持久化后端。
使用时需要注意什么(踩坑点)
-
元数据不持久化:默认内存 SQLite,容器重启 → namespace/table 注册信息全丢;MinIO 里 parquet/metadata.json 还在,但 Catalog 已"忘了"表。Demo 无所谓,真要用需挂 PostgreSQL 或换 Polaris,并给 SQLite/PG 挂 volume。
-
不是生产 Catalog:无多租户、无细粒度权限(OAuth 可接但不带 RBAC)、无 branch/merge 等 Nessie 能力、并发 commit 靠 SQLite 锁不扛高并发。
别上生产:无鉴权、无 RBAC、SQLite 内存不并发、重启即丢;生产换 Polaris/PG 等后端,上一轮已展开。
- catalog name 要对齐:fixture 默认服务名
rest_backend,Flink/Trino/PyIceberg 侧建的 catalog 名不一致会找不到,可用CATALOG_CATALOG_NAME=mycatalog覆盖。 - Flink 侧必须配套配 FileIO 与 S3:quickstart 里
io-impl=S3FileIO、s3.endpoint=minio:9000、path-style-access=true缺一不可,否则 REST 层能建表但写数据时报 S3 404/403。 - 端口与网络:容器内监听 8181,Flink 容器用服务名
http://iceberg-rest:8181而非localhost(localhost 是 Flink 自己)。 - 版本匹配:
apache/iceberg-rest-fixture镜像 tag 建议与 Flink/Iceberg runtime 大版本对齐(如 Iceberg 1.8 配 fixture 1.8.x),跨大版本 REST API 字段可能有差异。 - 日志噪音:默认 INFO 很吵,可
LOG_LEVEL=WARN或挂simplelogger.properties降噪。
简言之:quickstart 里的
iceberg-rest= Jetty 起的 Iceberg REST Catalog 参考实现 + 内存 SQLite 后端 + 对接 MinIO S3FileIO,作用是让 Flink 用标准 HTTP 协议管表,价值在多引擎互通验证;代价是"重启即失忆",只适合 Demo 不适合生产。
Iceberg + Flink + 对象存储的生产级项目中,Catalog 元数据系统的选型矩阵(2025–2026 共识)
| 方案 | 协议 | 元数据存储 | 凭证下发(vended-credentials) | RBAC/多租户 | Flink 适配 | 适用场景 |
|---|---|---|---|---|---|---|
| Apache Polaris(Incubating) | Iceberg REST | PostgreSQL(EclipseLink/JDBC) | ✅ 原生 | ✅ Principal Role + RBAC | ✅ RESTCatalog | 多引擎、自运维、vendor-neutral 首选 |
| Snowflake Open Catalog / Dremio Open Catalog | Iceberg REST | 托管 | ✅ | ✅ | ✅ | 不想运维 Polaris 本身 |
| AWS Glue + DynamoDB Lock | Glue 私有 RPC(新版带 REST 网关) | Glue 托管 + DynamoDB 行锁 | 经 IAM/Lake Formation | IAM 策略 | ✅ GlueCatalog | 全 AWS、Athena/EMR 强绑定 |
| Project Nessie | REST + 自研 | RocksDB/ Mongo/Postgres | ❌ | 基础 | ✅ RESTCatalog | 需要 Git 式 branch/多表原子提交 |
| Hive Metastore (HMS) | Thrift | HMS 后端 MySQL/PG | ❌ | 极弱 | ✅ HiveCatalog | 既有 Hadoop 集群、迁移过渡 |
| JDBC Catalog(PG/MySQL) | 直连 JDBC | 关系库表 | ❌ | ❌ | ✅ JdbcCatalog | 单/低并发、无多引擎、简单生产 |
| Hadoop Catalog | 文件系统 rename | 对象存储 version-hint.text | ❌ | ❌ | ✅ | 生产不推荐(对象存储 rename 非原子) |
-
结论:对象存储 + Flink 流式写入的生产场景,REST Catalog 是唯一兼顾"Flink/Spark/Trino 同一套 API、凭证不下发到 Flink TaskManager、可换后端不影响客户端"的路线。
-
在 Iceberg + Flink + 对象存储(S3/OSS/MinIO 等) 的生产架构里,Catalog 的选型原则:
- 新项目默认走 Iceberg REST Catalog(Polaris / 云厂商托管 REST / Nessie),Flink 侧统一用 RESTCatalog client;
- 只在"纯 AWS 且不想自运维"时考虑 Glue
- "已有 HMS 且不出 Hadoop 生态"才留 Hive
- JDBC Catalog 仅限中小规模或过渡。
3 使用指南
安装部署
CASE:Docker (Flink + Iceberg + MinIO) 【推荐】
CASE:Linux(Spark + Hadoop Catalog 本地最小 demo)
未亲测
# JDK 17/21,Spark 3.5+
export SPARK_VERSION=3.5.3
wget https://archive.apache.org/dist/spark/spark-$SPARK_VERSION/spark-$SPARK_VERSION-bin-hadoop3.tgz
tar -xzf spark-$SPARK_VERSION-bin-hadoop3.tgz
# 启动 spark-sql,挂载 iceberg 运行时
./spark-$SPARK_VERSION-bin-hadoop3/bin/spark-sql \
--packages org.apache.iceberg:iceberg-spark-runtime-3.5_2.12:1.11.0 \
--conf spark.sql.extensions=org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions \
--conf spark.sql.catalog.local=org.apache.iceberg.spark.SparkCatalog \
--conf spark.sql.catalog.local.type=hadoop \
--conf spark.sql.catalog.local.warehouse=/tmp/iceberg-wh
CASE:Windows
未亲测
- 不推荐原生 Windows 跑 Spark 写 S3;建议 WSL2 + Ubuntu 按上述 Linux 步骤;
- 纯 Python 分析可用
pip install pyiceberg,配置catalog.yaml指向本地 fs 或 Glue REST,无需 JVM。
Docker(Trino + Iceberg + MinIO 快捷栈)
未亲测
- 使用
trinodb/trino镜像,挂载etc/catalog/iceberg.properties:
connector.name=iceberg
iceberg.catalog.type=rest
iceberg.rest-catalog.uri=http://polaris:8181/api/catalog
关键操作
- 建表(V3 + 隐藏分区)
CREATE TABLE local.db.orders ( -- catalog = local , database = db , table = orders
id bigint,
user_id string,
amount decimal(10,2),
ts timestamp
) USING iceberg -- 声明这是一个 Iceberg 表,而不是 Spark / Hive 默认表; 其他样例值: USING hive , USING parquet
-- days(ts) 属于 partition transform,不会新增物理列
PARTITIONED BY (days(ts)) -- 作用:按天对 ts 字段做分区 ; days(ts) 是 Iceberg 的分区转换函数(transform); 实际生成的 partition 类似:ts_day=2025-01-15
TBLPROPERTIES ('format-version'='3'); -- 可选值: 1 / 2(目前阶段的主流版本) / 3
- 插入与时间旅行
INSERT INTO local.db.orders VALUES (1,'u1',9.9, timestamp('2026-07-31 09:00:00') );
SELECT * FROM local.db.orders FOR SYSTEM_VERSION AS OF 1;
- Schema 演进(不重写)
ALTER TABLE local.db.orders ADD COLUMN coupon string;
ALTER TABLE local.db.orders RENAME COLUMN amount TO total;
- 行级更新 / 合并
DELETE FROM local.db.orders WHERE id = 1;
MERGE INTO local.db.orders t
USING (SELECT 1 as id, 'u2' as user_id, 12.0 as total) s
ON t.id = s.id
WHEN MATCHED THEN UPDATE SET *
WHEN NOT MATCHED THEN INSERT *;
- 分区演变
ALTER TABLE local.db.orders ADD PARTITION FIELD hours(ts);
- 维护
CALL local.system.rewrite_data_files('db.orders');
CALL local.system.expire_snapshots('db.orders', TIMESTAMP '2026-07-01 00:00:00');
CALL local.system.remove_orphan_files('db.orders');
- PyIceberg 读
python install pyiceberg
from pyiceberg.catalog import load_catalog
cat = load_catalog("local", **{"type": "sql", "uri": "sqlite:///cat.db"})
tbl = cat.load_table("db.orders")
print(tbl.scan().to_arrow())
Z FAQ for Apache Iceberg
Q: Iceberg 和 Delta Lake / Hudi 到底差在哪?
A: Iceberg 核心是引擎中立的开放 spec + Catalog 抽象,Spark/Trino/Flink/Snowflake 同权;Delta 与 Spark/Databricks 耦合更深(虽 UniForm 可双向);Hudi 主打流式 CDC / 主键 upsert / 索引。【新建开放湖仓】多选 Iceberg,强 CDC 选 Hudi,已深度用 Databricks 可选 Delta。
Q: Iceberg 表“存在哪”? *
- 【数据文件】在对象存储(S3/OSS/COS)或 HDFS;
- 【元数据】 JSON/manifest 在同表目录下
metadata/; - 表名→metadata 的路径映射在
Catalog(HMS/Glue/REST)里。
三者分离,迁移数据时只要
Catalog指针可换即可。
Q: 为什么查询变慢了,是不是 Iceberg 不行?
- 多半是小文件过多 / snapshot 未过期 / delete 文件堆积 / catalog 用了弱一致 hadoop 类型。
先
rewrite_data_files+expire_snapshots+remove_orphan_files,并把 catalog 换为 REST/JDBC;Iceberg 本身规划比 Hive 目录扫描快一个量级。
Q: V2 表和 V3 表怎么选?
- 新表直接 format-version=3(1.11.0+),享受 Deletion Vector、Variant、Row Lineage;
- 老 V2 表不必强制升,但行级更新多的表升级后读放大显著下降。
Q: Catalog 用 Hadoop 行不行?
- 本地 demo 可以;生产不行——hadoop catalog 靠文件覆盖模拟原子,并发写易冲突。
- 生产用 Polaris / Nessie / Glue / JDBC / 云厂商 REST。
Q: 多引擎同时写会乱吗?
- 不会,只要共享同一个强一致 Catalog 并走 Iceberg 【乐观并发协议】;但不同引擎对 V3 特性支持度不同,写方用到的特性读方必须能解析,否则报错。
Q: Equality Delete/等值删除 vs. Position Delete/位置删除 vs. Deletion Vector/删除向量
| 维度 | Equality Delete (V2) | Position Delete (V2, V3 弃用) | Deletion Vector (V3+) |
|---|---|---|---|
| 标识方式 | 列值(如 user_id=42) | (file_path, pos) | 单 data file 的 Roaring Bitmap |
| writer 是否需要知道行位置 | 不需要 | 需要 | 需要 |
| 读时开销 | 类 join,随 delete 文件/行数放大 | 按 pos 跳过,O(1) | 单 bitmap 查位,O(1) |
| 积累后小文件数 | 无界增长 | 无界增长 | 每 data file 至多 1 个 |
| 典型生产者 | Flink CDC upsert、GDPR 按主键删、业务 DELETE | Spark/Trino 已知行号的点删 | V3 新表默认 |
| V4 走向 | 社区提议废弃 | 已被 DV 替代 | 唯一推荐行删机制 |
Q: AIGC时代下,4大开源数据湖格式,哪款更有竞争优势?哪款与Python数据生态结合更紧密?—— Apache Iceberg *
- 把 AIGC 时代(RAG 知识库、Embedding 表、多模态元数据、训练特征回放、Agent 审计快照)作为【场景约束】,四大开源表格式(Iceberg / Delta / Hudi / Paimon)的【竞争格局】和 【Python 亲密度】可以拆成两大结论:
- 综合竞争优势:Apache Iceberg 已是【开放湖仓事实标准】,AIGC 场景下凭"【引擎中立 + REST Catalog + V3 Variant/Row Lineage + PyIceberg 原生】"拿下最稳的基本盘;Paimon 在 Flink 原生流+湖内向量检索上差异化最强,Hudi 坚守 CDC/upsert 老巢,Delta 守 Databricks 围墙。
- Python 数据生态结合最紧:Iceberg(【PyIceberg】 + DuckDB 扩展 + Pandas/Ray/Arrow 直通),远超 delta-rs(社区维护)、
PyHudi(薄弱)、Paimon(几乎无原生 Python 客户端)。
AIGC 时代四维竞争力对照(2026 视角)
| 维度 | Apache Iceberg | Delta Lake | Apache Hudi | Apache Paimon |
|---|---|---|---|---|
| 治理与中立性 | ASF 治、REST Catalog/Polaris/Nessie 标准开放 | Linux 基金会但 Databricks 主导,Unity 闭源 | ASF 治,Onehouse 商业背靠 | ASF 治,阿里/Flink 系 |
| 多引擎平权 | Spark/Trino/Flink/Dremio/Snowflake/BigQuery/DuckDB 全通 | Spark 最优,外部靠 UniForm 转 Iceberg | Spark+Flink,Trino 弱 | Flink 原生,Spark 次之,其余弱 |
| 流/CDC/upsert | MoR+DV 够用,非设计原点 | CDF+DV,偏 Spark Streaming | MoR+record key 索引最强 | LSM 原生流写+changelog 最强 |
| AIGC 适配 | V3 Variant 存 chunk/metadata、_row_id 做 embedding 外键、DV 删文档不重写、时间旅行复现训练集 | 无 Variant,array |
1.2+ 原生 VECTOR/BLOB + ANN 索引 | 1.4 Lumina DiskANN 湖内向量检索 + BLOB 大对象 |
| 向量原生 | 否(交 Lance/Milvus,Iceberg 做底座) | 否 | 是(Hudi 1.2+) | 是(Paimon 1.4+) |
| Python 客户端 | PyIceberg(ASF 官方)、DuckDB iceberg 扩展、delta 无此待遇 | delta-rs(社区) | PyHudi 薄弱 | 基本无,靠 Java/Scala |
核心判断:
- "新项目默认 Iceberg" 在 2026 已是默认动作——Snowflake/BigQuery/S3 Tables/Athena/Glue 全站原生 Iceberg,反向兼容其他格式(Delta UniForm、Paimon Iceberg-compat 表面)全是"伪装成 Iceberg 被读",重力方向单向。
- AIGC 特化需求分裂:
- 做 RAG 知识库底座 + 多引擎共享 + Agent 审计时间旅行 → Iceberg(embedding 列用
array<float>或 V3 Variant 包 metadata,向量检索外挂 Lance/Milvus,Iceberg 管版本与权限)。 - 做 Flink 实时灌 embedding + 湖内 ANN + 多模态 BLOB → Paimon 1.4 更省事,不用自己拼 Lance。
- 做 CDC 业务库镜像给特征平台 → Hudi MoR 仍最便宜。
- 栈全在 Databricks → Delta 别动,UniForm 开一下对外可读即可。
- 做 RAG 知识库底座 + 多引擎共享 + Agent 审计时间旅行 → Iceberg(embedding 列用
4个数据湖格式都不是为向量检索设计的——Iceberg/Delta/Hudi 传统三强存 embedding 只是
array<float>列 + 暴力扫,真要 ANN 要么 【Paimon/Hudi】 的【内置索引】,要么 Iceberg+Lance/Milvus 分层。
Python 生态亲密度:Iceberg 断层领先
-
Iceberg
pyiceberg(Apache 官方子项目,非社区 fork):读有 filter pushdown、写 append/overwrite/merge、schema 演进、catalog 对接 REST/JDBC/Glue/SQLAlchemy,不依赖 JVM。- DuckDB
INSTALL iceberg直接ATTACH 's3://wh' AS ic TYPE iceberg后 Pandas DataFrame ↔ Iceberg 双向流动,RAG 脚本里边读边 MERGE embedding 很常见。 - 与
pandas、pyarrow、ray、daft、polars(通过 pyiceberg/arrow)链路通顺;LlamaIndex 有 Iceberg 集成示例做 RAG 版本化。 - Rust 实现
iceberg-rust还反哺 PyO3 绑定,Go 也有iceberg-go。
-
Delta Lake
deltalake(delta-rs 的 PyPI 包)能读能写能 vacuum,但非 Databricks 官方维护,Spark 外特性滞后(CDF、liquid cluster 不全),DuckDB 可读但非一等公民。
-
Hudi
PyHudi基本停留在实验层,生产 Python 作业多数还是起 Spark JVM 跑py4j,纯 Python 直连弱。
-
Paimon
- 没有成熟独立 Python 客户端,Flink/Spark 是入口;做 Python 数据科学要绕道 Spark Pandas UDF 或把 Paimon 当 Iceberg-compat 表用 PyIceberg 读(只读不写稳)。
所以,"Python 数据科学家/ML 工程师单机到湖仓"最顺的链路是:PyIceberg 写元数据 → Parquet 落 S3 → DuckDB 本地 OLAP → Pandas 训练 → 回写 Iceberg DV,这条链路只有 Iceberg 闭环。
AIGC 选型建议
- 企业级 开放 Lakehouse + RAG 底座 + 多团队多引擎共治 → Iceberg V3(Variant 存文档 metadata、
_row_id锚 embedding、DV 做软删、Polaris 做跨云鉴权)。 - Databricks 内 AIGC 流水线 → Delta + UniForm,别为"开放"硬迁。
- Flink 流灌向量 + 要湖内 ANN + 多模态 BLOB → Paimon 1.4(Lumina 索引省一套外挂)。
- 业务库 CDC → 特征/标签实时更新 → Hudi MoR 仍是最优解。
- 纯 Python Notebook 玩 embedding 表 → Iceberg + PyIceberg + DuckDB,不碰 JVM。
趋势层面:V4 Iceberg 在推 single-file commit / relative path / column families(单列族刷新 embedding 不重写整文件),进一步把"AI 表"的维护成本压下来;而 Delta/Hudi/Paimon 都在不同形式"说 Iceberg 语言",标准收敛方向已无悬念。
Y 推荐文献
- https://iceberg.apache.org/docs/latest/
- https://iceberg.org.cn/
- https://github.com/apache/iceberg
- https://www.ibm.com/cn-zh/think/topics/apache-iceberg
- https://www.dremio.com/blog/apache-iceberg-v4-efficiency-rewrite/
- https://lakeops.dev/blog/apache-iceberg-1-11-whats-new
- 《Apache Iceberg: The Definitive Guide》(Dremio 出品电子书)
X 参考文献
- https://iceberg.apache.org/ - iceberg.apache.org
- https://iceberg.org.cn/ - iceberg.org.cn
- https://github.com/apache/iceberg - GitHub
- https://iceberg.apache.org/docs/1.5.0/ - iceberg.apache.org
- https://www.ibm.com/cn-zh/think/topics/apache-iceberg - IBM
- https://www.dremio.com/blog/apache-iceberg-v4-efficiency-rewrite/ - Dremio
- https://lakeops.dev/blog/apache-iceberg-1-11-whats-new - LakeOps
- https://www.modern-datools.com/tools/apache-iceberg - Modern Data Tools
- https://iceberglakehouse.com/posts/iceberg-v4-state-july-2026 - iceberglakehouse
- https://dev.to/alexmercedcoder/apache-data-lakehouse-weekly-july-21-to-july-29-2026-p73 - dev.to
注:版本号与社区动态以 2026-07 为基准;V4 仍为提案态,生产请以 1.11.x + format-version 3 为准。
本文链接: https://www.cnblogs.com/johnnyzen
关于博文:评论和私信会在第一时间回复,或直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
日常交流:大数据与软件开发-QQ交流群: 774386015 【入群二维码】参见左下角。您的支持、鼓励是博主技术写作的重要动力!

浙公网安备 33010602011771号