1. Lakehouse 概述:从数据仓库到 Lakehouse 的演进

大家好,我是这次课程的主讲。今天咱们聊聊 Lakehouse 这个架构。

说实话,我刚入行那会儿,数据仓库和数据湖还是两个泾渭分明的概念。做数仓的看不起做数据湖的,觉得湖里全是“脏数据”;做数据湖的觉得数仓太死板,业务一变化就得改模型。嗯,这种“鄙视链”持续了好几年。

直到后来,大家发现——其实两边都有道理,也都有痛点。于是 Lakehouse 应运而生。

1.1 数据仓库的演进:从 OLTP 到 OLAP

数据仓库这个概念,最早可以追溯到 80 年代。那时候数据库主要是做交易处理的,也就是 OLTP。后来大家发现,跑报表和做分析的查询,跟交易查询完全是两码事。

我记得在 2015 年,我参与过一个零售项目的数仓建设。业务方要求 T+1 出报表,但底层还是用 MySQL 直接查。结果一到凌晨跑批,整个系统就卡死。后来我们上了专门的数仓方案,才把问题解决。

数据仓库的核心特点,我总结为三点:

  • Schema-on-Write:写入时就要定义好结构,数据必须“规规矩矩”进来
  • 强 ACID 事务:保证数据的一致性和可靠性
  • 面向分析优化:列式存储、预聚合、物化视图等

但数仓也有硬伤。最明显的就是——贵。存储贵、计算贵、扩展也贵。而且数据模型一旦定下来,改起来就像动手术。

1.2 数据湖的兴起:存储廉价,但管理混乱

后来 Hadoop 生态起来了,大家发现可以用廉价硬件存海量数据。数据湖的概念就这么火了。

数据湖的核心思想是:先把数据存下来,格式不限,结构不限。等要用的时候再处理。也就是 Schema-on-Read。

听起来很美好对吧?但我在项目中踩过不少坑。

⚠️ 我曾经踩过的坑:

有一次,业务方说“湖里有一张用户行为表,你直接查就行”。结果我跑了一个简单的 count,等了半小时没出结果。后来发现,那张表是几千个小文件拼起来的,而且数据质量极差——时间戳字段里混着中文、空值和负数。

这就是数据湖的典型问题:缺乏治理,数据沼泽。

数据湖的主要问题包括:

  • 不支持事务:并发写入容易出问题
  • 数据质量难保证:没有 Schema 约束,脏数据随便进
  • 性能不稳定:小文件问题、元数据膨胀
  • 缺乏统一的权限管理:谁都能读,谁都能写

1.3 Lakehouse 架构定义:鱼和熊掌我都要

Lakehouse 的出现,说白了就是想把数仓的“规整”和数据湖的“灵活”结合起来。

2017 年,Databricks 提出了 Lakehouse 的概念。核心思路是:在数据湖的廉价存储之上,增加一层“元数据层”和“事务层”,让湖里的数据也能像数仓一样被管理。

我个人理解,Lakehouse 有四个核心特征:

  1. 事务支持:ACID 特性,保证并发读写的一致性
  2. Schema 管理:支持 Schema 演进,但不允许脏数据
  3. 开放存储:数据以 Parquet/ORC 等开放格式存储,不被厂商锁定
  4. 统一批流:同一份数据,既能做批处理,也能做流处理

💡 一句话总结:Lakehouse = 数据湖的存储底座 + 数据仓库的管理能力 + 流批一体的计算引擎。

下面这张图,是我自己画的 Lakehouse 核心架构。你可以看到,底层是对象存储(比如 S3 或 HDFS),中间是表格式层(Delta Lake / Iceberg / Hudi),上层是计算引擎(Spark / Flink / Trino)。

Lakehouse 核心架构分层图 Lakehouse 核心架构分层 存储层(Storage Layer) 对象存储 / HDFS / 本地文件系统 表格式层(Table Format Layer) Delta Lake | Apache Iceberg | Apache Hudi ACID 事务 | Schema 管理 | 时间旅行 | 增量查询 计算引擎层(Compute Engine) Apache Spark | Apache Flink | Trino / Presto 应用层(Application Layer) BI 报表 | 实时大屏 | 数据科学 | 机器学习 流批 一体

1.4 Delta Lake 与 Apache Iceberg 对比

说到表格式层,目前最主流的就是 Delta Lake 和 Apache Iceberg。这两个我都用过,各有千秋。

先说说 Delta Lake。它是 Databricks 在 2019 年开源的,后来捐给了 Linux 基金会。Delta Lake 的核心是一个叫 Transaction Log 的东西,所有对表的操作都会记录在这个日志里。

我最早接触 Delta Lake 是在 2020 年,当时做一个实时数仓项目。业务要求数据写入后 5 分钟内就能查到,而且不能有重复。Delta Lake 的 Merge 操作 帮了大忙——upsert 语义天然支持,不用自己写去重逻辑。

再说 Apache Iceberg。它最早是 Netflix 开发的,2018 年开源,后来也捐给了 Apache 基金会。Iceberg 的设计哲学是“不依赖任何计算引擎”,所以它跟 Spark、Flink、Trino 都能很好地集成。

我个人觉得,Iceberg 最大的亮点是 分区演进。什么意思呢?就是你可以随时改分区策略,不用重写历史数据。这在 Delta Lake 里实现起来就比较麻烦。

下面这张表,是我根据实际使用经验整理的对比:

对比维度 Delta Lake Apache Iceberg
开源时间 2019 年(Databricks) 2018 年(Netflix)
事务实现 Transaction Log(JSON 格式) Manifest 文件 + Snapshot
Schema 演进 支持(列添加/删除/重命名) 支持(更灵活,支持嵌套结构)
分区演进 不支持(需重写数据) 支持(隐式分区,无需重写)
时间旅行 ✅ 支持(基于版本号) ✅ 支持(基于 Snapshot ID)
增量查询 ✅ 支持(CDC Feed) ✅ 支持(Incremental Read)
引擎兼容性 Spark 为主,Flink/Trino 有限 Spark / Flink / Trino / Hive 全支持
小文件合并 OPTIMIZE 命令(自动/手动) Rewrite Data Files(手动触发)
社区活跃度 高(Databricks 主导) 高(Apache 基金会 + 多家厂商)

💡 我的选型建议:

  • 如果你的技术栈以 Spark 为主,且团队对 Databricks 生态熟悉,选 Delta Lake 会更顺手。
  • 如果你的场景需要 多引擎混用(比如 Spark 做 ETL,Flink 做实时,Trino 做 Ad-hoc 查询),Iceberg 的兼容性更好。
  • 如果你对 分区演进 有强需求(比如业务分区策略经常变),Iceberg 是唯一选择。

1.5 一个简单的代码示例:用 Delta Lake 创建表

光说不练假把式。咱们看一段实际的代码。下面是用 Spark + Delta Lake 创建一张用户行为表的例子:

-- 创建 Delta 表
CREATE TABLE user_events (
  user_id    STRING,
  event_type STRING,
  event_time TIMESTAMP,
  page_url   STRING
)
USING DELTA
PARTITIONED BY (event_date STRING)
LOCATION 's3://my-lakehouse/user_events/';

-- 写入数据
INSERT INTO user_events VALUES
  ('u001', 'click', '2024-01-15 10:30:00', '/home'),
  ('u002', 'view',  '2024-01-15 10:31:00', '/product/123');

-- 查询历史版本(时间旅行)
SELECT * FROM user_events VERSION AS OF 1;

-- 合并数据(upsert)
MERGE INTO user_events AS target
USING updates AS source
ON target.user_id = source.user_id AND target.event_time = source.event_time
WHEN MATCHED THEN UPDATE SET *
WHEN NOT MATCHED THEN INSERT *;

这段代码看起来简单,但背后涉及的东西不少。比如 MERGE 操作,Delta Lake 内部会先做一次读取,判断哪些数据需要更新,哪些需要插入,然后生成新的数据文件,最后更新 Transaction Log。

嗯,这里要注意:如果表很大,MERGE 的性能可能会成为瓶颈。我建议在写入前先做一次数据去重,减少 Merge 的负担。

1.6 本章小结

咱们这一章聊了三个核心问题:

  • 数据仓库 规整但昂贵,适合结构化报表场景
  • 数据湖 灵活但混乱,适合原始数据存储
  • Lakehouse 取两者之长,用表格式层解决数据湖的治理问题

Delta Lake 和 Iceberg 是目前最主流的两个表格式方案。Delta Lake 强在 Spark 生态和易用性,Iceberg 强在引擎兼容性和架构灵活性。选哪个,取决于你的实际场景。