2. Lakehouse 架构基础:概念、核心特性与存算分离
好,咱们进入第二章。这一章我打算聊聊 Lakehouse 架构的基础。说实话,这个概念在圈子里已经炒了好几年了,但真正理解它的人,我觉得不算多。
很多人一上来就问我:“Lakehouse 不就是把数据湖和数据仓库拼在一起吗?” 嗯,这么说吧,对,也不全对。它更像是一种架构哲学,一种对数据管理方式的重新思考。
2.1 Lakehouse 到底是什么?
我个人习惯把 Lakehouse 理解为:在开放的数据湖存储上,实现了数据仓库的 ACID 事务和 SQL 分析能力。
你想想看,传统数据仓库(比如 Teradata、Greenplum)性能好,但贵,而且扩展性有限。数据湖(比如 HDFS、S3)便宜、能存海量数据,但缺乏事务支持,数据质量很难保证。
Lakehouse 就是来解决这个矛盾的。它把数据仓库的“表结构”和“事务”能力,直接搬到了数据湖的文件上。
核心定义: Lakehouse = 数据湖的存储底座 + 数据仓库的语义层 + 流批一体的计算引擎。
我在项目中遇到过不少团队,明明业务场景适合 Lakehouse,却还在用传统数仓硬扛。结果呢?存储成本高得吓人,扩容还得停机。说白了,就是架构选型没想清楚。
2.2 三大核心引擎:Delta Lake、Iceberg、Hudi
目前市面上主流的 Lakehouse 实现,就是这三个开源项目。它们本质上都是 表格式(Table Format),负责管理数据湖上的文件元数据。
我简单列个对比表,方便你快速理解差异:
| 特性 | Delta Lake | Apache Iceberg | Apache Hudi |
|---|---|---|---|
| 起源 | Databricks(2019) | Netflix(2018) | Uber(2016) |
| 核心存储 | Parquet + Delta Log | Parquet + Manifest 文件 | Parquet + Timeline |
| ACID 事务 | 乐观并发控制 | 乐观并发控制 | 基于时间线的并发 |
| 时间旅行 | ✅ 原生支持 | ✅ 原生支持 | ✅ 原生支持 |
| Schema 演进 | 支持(增删改列) | 支持(增删改列、重命名) | 支持(增删改列) |
| 增量查询 | 通过 Change Data Feed | 通过 Incremental Read | 通过增量拉取 |
| 与 Spark 集成 | 最紧密 | 良好 | 良好 |
| 与 Flink 集成 | 较晚,但已完善 | 原生支持 | 原生支持 |
这张表你看懂了吗?我重点说几个关键点:
- Delta Lake 的 Log 机制非常优雅,每次写操作都会生成一个 JSON 日志文件。我曾经帮一个客户排查数据不一致问题,就是靠回滚 Delta Log 搞定的。
- Iceberg 的 Manifest 分层设计,让它在超大规模表(比如几百 TB)上的查询性能非常稳定。我记得有一次做 POC,Iceberg 扫描 10 亿行数据,只用了不到 3 秒。
- Hudi 的 Copy-on-Write 和 Merge-on-Read 两种存储类型,很适合 CDC 场景。我自己的实时数仓项目,就经常用 Hudi 的 MOR 来平衡写入延迟和查询性能。
我的建议: 如果你的团队 Spark 技术栈比较强,优先考虑 Delta Lake。如果你们用 Flink 做实时,Iceberg 或 Hudi 会更顺手。别盲目追新,选你团队最熟悉的。
2.3 存储与计算分离:为什么是必须的?
好,接下来聊一个更底层的话题——存算分离。
传统数仓(比如 Oracle RAC、Greenplum)都是存算一体架构。什么意思呢?就是你的计算节点和存储节点绑在一起。扩容?你得同时加 CPU、内存和硬盘。缩容?也得一起减。
这种架构在云原生时代,简直就是灾难。你想想看:
- 计算资源是弹性的,白天忙就多开几个节点,晚上闲就缩回去。
- 存储资源是持久化的,数据一旦写入,就得一直保留。
存算一体,意味着你没法独立扩缩。要么浪费计算资源,要么浪费存储资源。
Lakehouse 的存算分离,说白了就是:计算集群只管算,存储集群只管存。它们通过对象存储(S3、OSS、HDFS)或者网络文件系统连接。
我画了一张图,帮你理解这个架构:
你看这张图,从上到下三层:
- 计算层:Spark、Flink、Presto 这些引擎,按需启动,用完就释放。
- 表格式层:Delta Lake、Iceberg、Hudi 负责管理文件元数据,提供 ACID 和 Schema 能力。
- 存储层:对象存储或 HDFS,只存数据文件,不关心谁在算。
这样做的好处太明显了:
- 计算资源可以缩到 0,晚上没任务就不花钱。
- 存储可以无限扩展,加硬盘就行,不用动计算。
- 同一个数据,可以被多个计算引擎同时访问。
避坑指南: 我曾经帮一个客户做存算分离改造,结果发现他们的网络带宽只有 1Gbps。对象存储的延迟本来就比本地盘高,网络再一瓶颈,查询性能直接崩了。所以,存算分离的前提是网络要够快,至少 10Gbps 起步。
2.4 为什么 Lakehouse 适合 CDC 实时同步?
好,回到咱们课程的主题——CDC 实时同步。Lakehouse 为什么特别适合这个场景?
原因有三:
- ACID 事务:CDC 数据是流式写入的,如果没有事务,很容易出现部分写入、数据不一致的问题。Lakehouse 的表格式层保证了写入的原子性。
- 时间旅行:CDC 数据经常需要回溯历史状态。比如你想看某个订单在 10 分钟前的快照,Lakehouse 直接支持按时间戳查询。
- 增量查询:CDC 的本质就是增量数据。Delta Lake 的 Change Data Feed、Iceberg 的 Incremental Read、Hudi 的增量拉取,都是为这个场景设计的。
我记得有一次做实时数仓项目,业务方要求数据延迟不超过 5 分钟,同时还要支持 7 天内的任意时间点回溯。用传统数仓,要么存不下,要么查不动。最后我们用 Iceberg + Flink CDC 搞定了,效果非常好。
一句话总结: Lakehouse 的存算分离 + 表格式层,让 CDC 实时同步变得既便宜又可靠。这也是为什么现在越来越多的团队,把实时数仓从 Kudu 或 ClickHouse 迁移到 Lakehouse 上。