数据湖与开放表格式 — 系列规划
本文是写作规划,不是可发布正文。拆解对象分两层:列式文件格式(Parquet 主、ORC/Arrow 对照)与开放表格式(Iceberg 主线,Delta / Hudi 对照)。不写 SQL/BI 教程,不写云厂商托管湖仓内部实现。
关联文档:
index.md(读者入口)。本文件聚焦逐章大纲、来源台账、实验台账与写作顺序。
一、为什么写这个系列
1.1 数据库栈的缺口
| 已有内容 | 引擎/视角 | 落点 |
|---|---|---|
postgresql-kernel/ (26) |
行存 OLTP | B-Tree + MVCC + WAL |
db/mysql-innodb/ (20) |
行存 OLTP | InnoDB 页/Redo/Undo |
db/lsm-tree/ (9) |
写优化 KV | MemTable + SSTable + Compaction |
db/columnar-engine/ (16) |
读优化列存 | ClickHouse MergeTree / DuckDB |
storage/ (79) |
通用存储原理 | 含对象存储但未落到表格式 |
db-frontier/ (25) |
AI 原生 DB 前沿 | 向量/HTAP,非表格式内核 |
结论:读者掌握了「数据在引擎进程里」的行存、写优化、列存之后,缺的是另一种范式——数据以文件形式躺在对象存储上,靠一层独立的「表格式」元数据获得 ACID、更新、快照、时间旅行。这正是 lakehouse 的内核问题,目前全站没有系统拆解。
1.2 为什么选 Iceberg(主)+ Delta / Hudi(对照)
| 维度 | Iceberg | Delta Lake | Hudi |
|---|---|---|---|
| 元数据模型 | 不可变 snapshot + manifest 树 | 顺序事务日志 _delta_log |
timeline + file group |
| 规范开放度 | 表规范 + REST Catalog 规范公开 | 协议公开,生态偏 Spark/Databricks | 协议公开,生态偏流式 upsert |
| 行级更新 | position/equality delete、V3 deletion vector | deletion vector | CoW / MoR + record index |
| 引擎中立性 | 最强(Trino/Spark/Flink/DuckDB/CH) | 较强(UniForm 补互通) | 偏自带写入栈 |
| 系列篇幅 | 主线 4 章(08–11) | 对照 1 章(12) | 对照 1 章(13) |
选 Iceberg 作主线:规范最完整、引擎最中立、2024–2026 事实上的收敛点;Delta/Hudi 各一章讲清「同一问题的不同解法」,第 14 章做对照与互通(UniForm / XTable)。
1.3 系列定位
Lakehouse = 列式文件格式 + 对象存储语义 + 表格式元数据 + catalog + 查询引擎
不写 SQL 教程,写:
- 一个 Parquet 文件如何切 row group / page,谓词如何在读盘前裁掉数据。
- S3 不能原子 rename、list 很贵,表格式怎么在这种存储上做原子提交与快照隔离。
- snapshot 树 / 事务日志 / timeline 三种元数据模型各自的取舍。
- 行级删除的三条路线:copy-on-write、merge-on-read、deletion vector。
二、核心问题与目标读者
2.1 六个关键问题
列式文件在对象存储上如何组织、又如何在读取前被裁剪? → 第 2、3、4、5 章:row group / page、column index、bloom filter、谓词与投影下推。
没有数据库进程,怎么在对象存储上做 ACID 与并发控制? → 第 6、7、11、12 章:S3 语义、原子指针 swap、乐观并发、事务日志。
Iceberg / Delta / Hudi 的元数据模型差在哪? → 第 8–14 章:snapshot 树 vs 顺序日志 vs timeline。
行级 update / delete 在湖上怎么实现? → 第 10、12、13 章:CoW、MoR、position/equality delete、deletion vector、record index。
catalog、查询引擎、流式写入如何拼成可运维的湖仓? → 第 15、18、19、20 章:catalog 语义、引擎下推、CDC 入湖、运维故障模式。
湖仓如何承接 AI / 向量负载? → 第 21 章:训练数据存湖、Lance 等向量优化格式、湖上向量检索边界。
2.2 目标读者
- 数据平台 / 数据工程师,从数仓 / OLAP 转型的开发者,做表格式选型的架构负责人。
- 先修:SQL、列存直觉(建议先读
db/columnar-engine)、对象存储基本概念。 - 不假设:已有 Iceberg/Delta/Hudi 生产经验。
三、篇目结构(全 21 篇)
第一部分:列式文件格式(第 1–5 章)
第 1 章:Lakehouse 全景:从 Hive 表到开放表格式
- Hive 目录式分区表的三个硬伤:无原子提交、依赖目录 list、schema/分区演进要重写。
- Lakehouse 的分层:不可变数据文件(Parquet)+ 可变元数据指针(表格式)+ catalog。
- 「data lake / data warehouse / lakehouse」概念边界,不做营销式定义。
- 全系列地图:文件格式层 → 对象存储层 → 表格式层 → catalog/引擎层。
- 来源:Iceberg 论文/设计文档对 Hive 表问题的描述;Hive Metastore 文档。
第 2 章:Parquet 文件格式深拆
- 物理结构:file → row group → column chunk → page(data
page / dictionary page);footer 中的
FileMetaData(Thrift)、magicPAR1。 - 编码:PLAIN、RLE/bit-packing 混合、字典编码、DELTA_BINARY_PACKED、BYTE_STREAM_SPLIT。
- 嵌套数据:Dremel 的 repetition/definition levels。
- 裁剪元数据:column index / offset index(page 级 min/max)、split-block bloom filter。
- 谓词下推与投影下推如何利用上述结构。
- 来源:
apache/parquet-format(Thrift 定义、编码规范)、parquet-mr / arrow 实现。 - 实验:用
pyarrow写一个多 row group 文件,parquet-tools/pqrsdump footer 与 page index,记录真实字段。
第 3 章:ORC 文件格式与 Parquet 对照
- 结构:file → stripe →(index streams / data streams / stripe footer);postscript + file footer。
- row index(默认每 10000 行一组)、stripe/row-group 级 min/max、bloom filter。
- 与 Parquet 的差异:stripe vs row group、流式 stream 组织、生态(Hive 系 vs 通用)。
- 选型边界:什么场景仍用 ORC。
- 来源:
apache/orc规范与文档。 - 实验:同一数据集写 ORC 与 Parquet,对比文件结构与体积(标注 schema、压缩、行数)。
第 4 章:Apache Arrow 内存格式与零拷贝
- 内存列式布局:validity bitmap + value buffer + offset buffer(变长/嵌套)。
- IPC 格式(streaming / file)、Arrow Flight(gRPC)、C Data Interface 的跨语言零拷贝。
- Arrow 与 Parquet 的分工:内存计算格式 vs 磁盘存储格式,二者如何衔接(read 到 Arrow 批)。
- DataFusion / Polars / Acero 以 Arrow 为基座的意义。
- 来源:Arrow 官方格式规范(Columnar Format、IPC、C Data Interface)。
- 实验:用 C Data Interface 在两个进程/语言间零拷贝传递一个 RecordBatch,验证 buffer 地址。
第 5 章:列式编码与压缩
- 字典、delta、RLE、bit-packing 的适用列类型与组合方式。
- 块压缩:SNAPPY / ZSTD / LZ4 / GZIP 的压缩比与解压吞吐取舍。
- 与
columnar-engine/03-compression-encoding(ClickHouse 编码)对照:同思想、不同落地。 - 来源:Parquet 编码规范、压缩库官方文档。
- 实验:同一列在不同编码+压缩组合下的体积与读取耗时(本机,≥3 轮取中位数,交代环境)。
第二部分:对象存储与 ACID 基础(第 6–7 章)
第 6 章:对象存储语义与代价
- S3 一致性模型(强读写一致后的现状)、LIST 的 O(prefix) 代价、没有原子 rename(copy+delete)。
- 条件写(If-None-Match / If-Match)对提交协议的意义。
- multipart upload、对象不可改写、与 POSIX 文件系统的关键差异。
- MinIO / 兼容 API 的差异点。
- 来源:AWS S3 官方文档(一致性、条件请求、multipart)。
- 实验:在 MinIO 上测 LIST 在不同对象数下的耗时、模拟 rename 代价(标注对象规模)。
第 7 章:表格式为什么存在
- 目录式分区表的并发写竞争、partial commit、list-based planning 的代价。
- 表格式补上的四件事:原子提交、快照隔离、文件级统计裁剪、schema/分区演进。
- 「元数据指针 + 不可变数据文件」这一共性抽象(三家都遵循)。
- 来源:Iceberg/Delta/Hudi 设计文档对各自动机的陈述。
第三部分:Iceberg 内核(第 8–11 章)
第 8 章:Iceberg 元数据树
- 四层:catalog 指针 →
vN.metadata.json→ manifest list(= snapshot)→ manifest files → data files。 - snapshot、manifest 中的分区数据与列级 stats(lower/upper bound、null count、value count)。
- 一次读如何从 snapshot 逐层收敛到文件集合(metadata planning,不 list 目录)。
- 表规范 V1/V2/V3 的版本边界总览(细节在第 10 章)。
- 来源:Iceberg
表规范(spec)、
apache/iceberg源码(标注 1.x release)。 - 实验:用 Spark/pyiceberg 建表后写几次,逐层打开 metadata.json / manifest,画出树。
第 9 章:隐藏分区与分区演进
- partition spec 与 transform:identity、bucket[N]、truncate[W]、year/month/day/hour、void。
- 隐藏分区如何让查询不写分区列谓词也能裁剪,避免「分区裂脑」。
- 分区演进为何不重写历史数据(spec 演进 + 文件携带所属 spec)。
- 与 Hive 静/动态分区的对比。
- 来源:Iceberg 规范的 partitioning/transform 章节。
- 实验:建隐藏分区表,演进 spec 后观察新旧文件的 partition 数据与查询计划。
第 10 章:行级删除与 Merge-on-Read
- position delete vs equality delete 的语义与代价。
- copy-on-write vs merge-on-read 的写放大/读放大取舍。
- V2 delete file 与 V3 deletion vector(Puffin 承载)的差异与迁移。
- 读路径如何把 data file + delete 合并出可见行。
- 来源:Iceberg 规范 row-level deletes、V3 deletion vector 提案/规范,Puffin 格式规范。
- 实验:MoR 表执行 delete/update,检查生成的 delete file,对比 CoW 重写文件量。
第 11 章:提交协议与并发控制
- 提交 = catalog 对元数据指针做 compare-and-swap(原子 swap)。
- 乐观并发:基于当前 snapshot 生成新 snapshot,冲突则按隔离级别重试。
- 不同 catalog 的原子性来源(DB 行锁、REST 后端、对象存储条件写)。
- 写隔离级别(serializable / snapshot)与冲突检测维度。
- 来源:Iceberg 规范 commit/conflict、REST Catalog OpenAPI 规范。
- 实验:两个并发 writer 提交,制造冲突观察重试与失败。
第四部分:Delta 与 Hudi(第 12–14 章)
第 12 章:Delta Lake 事务日志
_delta_log:有序 JSON commit(actions:add/remove/metaData/protocol/commitInfo/txn)+ 每 N 次 parquet checkpoint。- protocol 版本与 table features(reader/writer features)。
- deletion vector(Delta 的 MoR)、liquid clustering 与 Z-order。
- 乐观并发与冲突检测如何基于日志做。
- 来源:Delta
协议规范(PROTOCOL.md)、
delta-io/delta源码(标注 3.x+)。 - 实验:建 Delta 表写多次,打开
_delta_log的 JSON 与 checkpoint,读 protocol。
第 13 章:Apache Hudi
- 表类型:CoW vs MoR(base file + log file + compaction)。
- timeline:instant(commit/deltacommit/compaction/clean/rollback)在
.hoodie/。 - file group / file slice 模型。
- 索引体系:bloom index、simple、record-level index、bucket index——为何 Hudi 强在 upsert。
- 查询类型:snapshot / incremental / read-optimized。
- 来源:Hudi 官方文档与设计文档、
apache/hudi源码(标注 1.x)。 - 实验:MoR 表做 upsert,观察 log file 与 compaction 后的 base file。
第 14 章:三者对照与互通
- 元数据模型、行级更新、并发、引擎生态四维对照表(带口径)。
- 互通方案:Delta UniForm(同时生成 Iceberg/Hudi 元数据)、Apache XTable(元数据转换)。
- 选型决策树(按写入模式、引擎栈、更新频率),不做排名。
- 来源:UniForm / XTable 官方文档与规范,三家规范对照。
第五部分:治理、引擎、集成与前沿(第 15–21 章)
第 15 章:Catalog 之争
- catalog 职责:表名 → 当前元数据指针 + 原子提交点。
- 形态对比:Hive Metastore、Iceberg REST Catalog、JDBC catalog、Hadoop(file-based,并发风险)、AWS Glue、Nessie(类 git 分支/标签)、Gravitino。
- 单列:Apache Polaris(Snowflake 开源、REST Iceberg catalog)与 Unity Catalog(Databricks 2024 开源)的最新形态、治理/权限模型、与 REST 规范的关系及互通。
- 锁与原子性语义差异、多引擎共享的兼容性。
- 来源:各 catalog 官方文档、Iceberg REST Catalog 规范、Polaris/Unity 官方文档(标注版本与开源时间)。
第 16 章:时间旅行、schema 与分区演进
- snapshot 过期(expire)、回滚(rollback)、按时间/快照读。
- schema evolution 规则(按 field ID 增删改名重排,不靠位置)。
- 演进对老数据/老 reader 的兼容边界与陷阱。
- 来源:Iceberg/Delta 规范的 evolution 与 time travel 章节。
- 实验:演进 schema 后读旧 snapshot,验证字段映射。
第 17 章:小文件与 Compaction
- 小文件根因:频繁提交、流式写入、过细分区。
- 操作:bin-pack rewrite、sort/z-order/clustering rewrite、rewrite manifests、expire snapshots、remove orphan files。
- 统计信息维护:Puffin 中的 NDV sketch(如 Theta)对 planning 的影响。
- 来源:Iceberg
rewrite_data_files/rewrite_manifests文档、Puffin 规范、Delta OPTIMIZE 文档。 - 实验:构造大量小文件后 compaction,对比文件数与查询 planning 耗时。
第 18 章:查询引擎如何读湖
- 下推链路:partition pruning(manifest)→ file pruning(manifest stats)→ row-group/page pruning(Parquet column index)→ 字典过滤。
- 引擎对照:Trino、Spark、DuckDB、DataFusion、ClickHouse 读 Iceberg/Delta 的能力与差异。
- planning 在哪一层完成、stats 来自哪。
- 来源:各引擎 connector 文档、Trino Iceberg connector、DuckDB iceberg/delta 扩展文档。
- 实验:同一查询在 Trino 与 DuckDB 上的扫描文件数/数据量对比(标注数据集与版本)。
第 19 章:流式写入与 CDC 入湖
- sink:Flink Iceberg/Hudi/Delta sink、Kafka Connect Iceberg sink、Spark Structured Streaming。
- exactly-once:Flink checkpoint 与表格式提交如何对齐(幂等提交)。
- CDC 入湖:Debezium → Kafka → upsert(equality delete / Hudi record index)。
- 流式写入与小文件、compaction 的拉扯及缓解。
- 来源:Flink/Iceberg、Kafka Connect、Hudi DeltaStreamer 文档。
- 实验:本机 Flink/Kafka 小规模流式写 Iceberg,观察提交频率与小文件。
第 20 章:选型、迁移与运维
- 从 Hive 表迁移(in-place migrate / add_files / 重写)路径与风险。
- benchmark 口径与陷阱(cache、文件布局、stats 是否新鲜)。
- 生产故障模式:孤儿文件、元数据膨胀、提交冲突风暴、过期快照清理误删、catalog 单点。
- 运维清单:compaction 调度、snapshot 保留、监控指标。
- 来源:Iceberg 迁移文档、各家运维文档、公开事故复盘(标注来源与版本)。
第 21 章:湖上 AI 与向量
- 湖作为 AI 底座:embedding / 特征 / 训练样本以列式文件存湖,训练读取与可复现(按 snapshot 固定数据版本)。
- 向量优化格式:Lance 等面向随机访问与向量检索的文件格式,与 Parquet 的取舍(顺序扫描 vs 点查/向量召回)。
- 在 Iceberg/Parquet 上做向量检索的现状与限制:ANN 索引存放、过滤下推、与专用向量库的边界。
- 与
db-frontier(向量引擎、HTAP)的衔接边界:本章只讲「湖侧存储与读取」,不重复向量索引算法。 - 来源:Lance / lancedb 文档与格式说明、Iceberg
社区关于向量/ML 数据的提案、
db-frontier向量篇。 - 实验:将一批 embedding 写成 Lance 与 Parquet,对比顺序扫描与按 id 随机点查的耗时(标注维度、行数、环境)。
四、依赖关系
1 → 2 → 3
2 → 4 → 5
1 → 6 → 7 → 8 → 9
8 → 10 → 11
7 → 12
7 → 13
10,12,13 → 14
11 → 15
9 → 16
5 → 17
14,15 → 18
10 → 19
18,19 → 20
2,8,18 → 21
五、阅读路径
| 路径 | 篇目 | 适合 |
|---|---|---|
| 数据平台工程师 | 1→2→8→17→18→20 | 端到端建湖 |
| 从 OLAP / 列存来 | 2→4→8→10→14 | 文件格式衔接表格式 |
| 流式 / 实时入湖 | 1→8→10→19 | CDC 与小文件 |
| 表格式选型 | 1→8→12→13→14→15 | Iceberg/Delta/Hudi 取舍 |
| 湖上 AI / 向量 | 2→8→18→21 | 把湖当训练/检索底座 |
| 完整通读 | 1→…→21 | 系统掌握 |
六、来源台账
A 级
- Apache Parquet format
规范(
apache/parquet-format,Thrift 定义、编码规范)。 - Apache ORC 规范与文档。
- Apache Arrow 官方规范(Columnar Format、IPC、C Data Interface、Flight)。
- Apache Iceberg 表规范(V1/V2/V3)、REST Catalog
OpenAPI、Puffin 规范、
apache/iceberg源码(标注 1.x release)。 - Delta Lake
协议规范(PROTOCOL.md)、
delta-io/delta源码(标注 3.x+)。 - Apache Hudi 官方文档与
apache/hudi源码(标注 1.x)。 - AWS S3 官方文档(一致性模型、条件请求、multipart)。
B 级
- Iceberg/Delta/Hudi 维护者与厂商工程博客(须标注版本与日期)。
- 公开事故复盘与会议演讲(SIGMOD/VLDB/各家 tech talk)。
禁止
- 无版本上下文的厂商营销页单独支撑结论。
- 未实测的性能倍数写进正文。
- 把演进中的 V3 特性当稳定结论。
七、实验台账
| 章 | 实验 |
|---|---|
| 2 | Parquet footer / page index / bloom filter dump |
| 3 | ORC vs Parquet 结构与体积对照 |
| 4 | Arrow C Data Interface 零拷贝传递 |
| 5 | 编码+压缩组合的体积/读取耗时(≥3 轮中位数) |
| 6 | MinIO 上 LIST 与 rename 代价随对象数变化 |
| 8 | Iceberg metadata.json/manifest 逐层 dump |
| 9 | 分区演进前后文件 partition 数据 |
| 10 | MoR delete file vs CoW 重写量 |
| 11 | 并发提交冲突与重试 |
| 12 | Delta _delta_log JSON/checkpoint 解读 |
| 13 | Hudi MoR upsert 与 compaction |
| 17 | 小文件 compaction 前后文件数与 planning 耗时 |
| 18 | Trino vs DuckDB 扫描文件数对比 |
| 19 | Flink 流式写 Iceberg 的提交频率与小文件 |
| 21 | Lance vs Parquet 顺序扫描与随机点查耗时 |
每个 benchmark 交代:CPU、内存、OS、组件版本、数据集规模、采样轮次(≥3,取中位数),外部数据明确标注引用。
八、系列联动
| 系列 | 联动 |
|---|---|
db/columnar-engine/ |
向量化执行、编码压缩、Parquet 与 MergeTree 文件格式对照 |
storage/ |
对象存储、压缩、冷热分层 |
db-frontier/ |
向量引擎、HTAP、湖上 AI 负载 |
distributed/ |
一致性模型、乐观并发与原子提交 |
db/postgresql-kernel/、db/mysql-innodb/ |
行存 MVCC 对照「湖上 ACID」 |
九、边界
不承诺
- 替代 Iceberg/Delta/Hudi 官方文档。
- 云厂商托管湖仓(managed Iceberg/Delta)内部实现与实时定价。
- Spark/Flink/Trino 批流框架全文教程。
- 业务建模与数仓分层方法论。
承诺
- 以「文件 + 元数据 + 提交协议」的内核视角组织,不停留在概念科普。
- 关键结论锚定规范条款、源码或实测。
- 选型章写能力边界与 lock-in 风险,不做排名榜。
十、写作顺序
index.md(已完成)- 第 1 章(全景,不依赖实测,先开篇)
- 第 2、3、4、5 章(文件格式层,基础阻塞最多)
- 第 6、7 章(对象存储与表格式动机)
- 第 8、9、10、11 章(Iceberg 主线)
- 第 12、13、14 章(Delta/Hudi 对照与互通)
- 第 15、16、17 章(catalog 与治理)
- 第 18、19、20 章(引擎、流式、运维收束)
- 第 21 章(湖上 AI 与向量,前沿收尾,可在 18 完成后并行)
十一、已确认决策(2026-06-30)
- 版本锚定:Iceberg 1.x + 表规范 V2 主线、V3 特性标注,确认采用。
- Hudi:保持 1 章(第 13 章),不扩成 2 章。
- 流式边界:第 19 章只讲「入湖侧」(sink、exactly-once 提交、CDC upsert、小文件),流处理引擎本身的窗口/状态/容错留给未来可能的独立「流处理」系列,不在本系列展开。
- catalog:第 15 章单列 Apache Polaris 与 Unity Catalog 开源后的最新形态,其余 catalog 作对比背景。
- 湖上 AI / 向量:新增第 21
章作为前沿收尾,只讲湖侧存储与读取(含
Lance),向量索引算法仍归
db-frontier。
系列规模由此定为 21 篇。
规划版本:v2,2026-06-30(全 21
篇,待确认问题已闭环)
目录:post/db/lakehouse/
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【数据湖与开放表格式】Parquet · Iceberg · Delta · Hudi 内核拆解
拆解 lakehouse 的两层基础:列式文件格式(Parquet/ORC/Arrow)与开放表格式(Iceberg/Delta/Hudi)。讲清没有数据库进程时,如何在对象存储上做 ACID、行级更新、快照与并发,以及 catalog、查询引擎、流式入湖如何拼成可运维的湖仓。面向数据平台工程师与从 OLAP/数仓转型的开发者。