2. Lakehouse 核心概念:数据湖与数据仓库的融合
好,咱们进入第二章。这一章要聊的,是整个 Lakehouse 架构的根基——数据湖和数据仓库到底怎么融合?说白了,就是要把数据湖的灵活性和数据仓库的可靠性捏到一块儿。
我最早做数据平台的时候,团队还在纠结“到底用湖还是用仓”。后来发现,这不是二选一的问题。你想想看,业务部门既要海量原始数据做探索,又要报表数据保证一致性,一个方案解决不了所有问题。所以 Lakehouse 这个思路就出来了——把湖的廉价存储和仓的 ACID 事务结合起来。
2.1 数据湖 vs 数据仓库:核心差异
先看一张对比表,把两者的区别理清楚。我在项目中见过不少团队,把数据湖当仓库用,结果数据质量一塌糊涂。
| 维度 | 数据湖 | 数据仓库 |
|---|---|---|
| 数据格式 | 原始格式(JSON、CSV、Parquet 等) | 结构化、Schema-on-Write |
| 事务支持 | 无或弱(最终一致性) | 强 ACID 事务 |
| 更新能力 | 追加为主,更新困难 | 支持 UPDATE/DELETE |
| 适用场景 | 数据探索、机器学习、原始日志 | BI 报表、固定查询、数据治理 |
| 存储成本 | 低(对象存储为主) | 高(专用存储引擎) |
这张表你看完应该能明白,数据湖的优势是“便宜、能装”,但缺点也很明显——数据写进去之后,想改个字段都费劲。数据仓库正好相反,贵但靠谱。
核心观点:Lakehouse 不是要消灭数据湖或数据仓库,而是把两者的优点组合起来。湖提供存储底座,仓提供事务和查询能力。
2.2 融合的关键:事务层
那怎么融合呢?关键就在“事务层”。数据湖本身没有事务能力,但我们可以加一层元数据管理,让湖上的文件操作具备原子性和隔离性。
我个人习惯把 Lakehouse 的架构分成三层:
- 存储层:对象存储(S3、ADLS、OSS),存 Parquet/ORC 文件。
- 事务层:管理文件版本、事务日志、Schema 演化。
- 查询层:Spark、Presto、Flink 等引擎,读取事务层提供的快照。
事务层就是 Delta Lake 和 Iceberg 这类工具干的事。它们给数据湖装上了“版本控制”和“事务日志”,让湖上的数据操作变得像数据库一样可靠。
一个小技巧:刚开始接触 Lakehouse 时,别急着上复杂架构。先用 Delta Lake 或 Iceberg 管理一张表,跑通“读-写-更新”流程,感受一下事务层带来的变化。
2.3 Delta Lake 简介
Delta Lake 是 Databricks 开源的项目,也是 Spark 生态里最成熟的 Lakehouse 方案。它的核心设计是 事务日志(Transaction Log),记录每次对表的操作。
举个例子,你往 Delta 表里插入一批数据,Delta Lake 会做三件事:
- 把数据写成 Parquet 文件存到存储层。
- 在事务日志里追加一条记录,说明“新增了哪些文件”。
- 查询时,只读取日志里最新的文件列表。
这样做的好处很明显——如果写入中途失败,日志里没有提交记录,查询就看不到脏数据。这就是 ACID 的原子性。
我记得有一次,生产环境的数据管道因为网络抖动中断了。如果用普通数据湖,那批半拉子数据就留在那了,后续查询全乱套。但 Delta Lake 的事务日志自动回滚了未提交的操作,数据完整性一点没受影响。
2.3.1 Delta Lake 的核心特性
| 特性 | 说明 |
|---|---|
| ACID 事务 | 支持并发读写,保证数据一致性 |
| Schema 演化 | 可以动态增删字段,不用重建表 |
| 时间旅行 | 查询历史版本的数据,用于回溯或审计 |
| 数据版本控制 | 每次操作生成一个新版本,可回滚 |
注意:Delta Lake 的事务日志默认存储在表目录下的 _delta_log 文件夹里。如果误删了这个文件夹,整个表就废了。我曾经见过有人手滑删了日志目录,结果只能从备份恢复。所以,一定要给事务日志目录设置权限保护。
2.4 Apache Iceberg 简介
Apache Iceberg 是另一个主流的事务层方案,由 Netflix 和 Airbnb 等公司贡献。它的设计思路和 Delta Lake 类似,但更强调 表格式的标准化 和 多引擎兼容。
Iceberg 的核心也是事务日志,但它把元数据分成了三层:
- 元数据文件(Metadata File):记录表的 Schema、分区信息、快照列表。
- 清单列表(Manifest List):每个快照对应的文件清单。
- 清单文件(Manifest):具体的数据文件路径和统计信息。
这种分层设计让 Iceberg 在查询时能快速过滤掉不相关的文件。比如你查某一天的数据,Iceberg 通过清单里的统计信息,直接跳过其他分区的文件,性能提升很明显。
我个人的经验是,如果你的团队用 Spark 为主,Delta Lake 上手更快;如果你们有多引擎需求(比如 Spark 写、Presto 读、Flink 流处理),Iceberg 的兼容性更好。
2.4.1 Iceberg 的核心特性
| 特性 | 说明 |
|---|---|
| 隐藏分区 | 自动根据数据值计算分区,用户不用手动指定 |
| 快照隔离 | 每个查询基于一个快照,读写互不干扰 |
| Schema 演化 | 支持列添加、删除、重命名,不重写数据 |
| 多引擎支持 | Spark、Flink、Trino、Hive 等都能读 |
2.5 Delta Lake vs Iceberg:怎么选?
这个问题我经常被问到。说实话,没有的答案,但可以给你一些参考:
| 对比维度 | Delta Lake | Apache Iceberg |
|---|---|---|
| 生态绑定 | 与 Spark 深度集成 | 引擎无关,兼容性更广 |
| 事务日志 | JSON 格式,存储在表目录 | 分层元数据,独立管理 |
| 性能优化 | Z-Order 排序、文件合并 | 隐藏分区、文件剪枝 |
| 社区活跃度 | Databricks 主导,更新快 | Apache 基金会,厂商中立 |
我的建议:如果你们公司已经重度使用 Databricks 或 Spark,选 Delta Lake 更省心。如果你们有多引擎、多云的需求,或者希望避免厂商锁定,Iceberg 是更稳妥的选择。
2.6 核心架构图:Lakehouse 事务层
下面这张图展示了 Lakehouse 的核心架构,重点看事务层怎么连接存储和查询。
2.7 避坑指南:我踩过的几个坑
最后分享几个实战中容易踩的坑,希望能帮你少走弯路。
- 事务日志膨胀:Delta Lake 和 Iceberg 的日志文件会随着操作次数增加而变大。我曾经遇到过一张表操作了上万次,日志文件比数据文件还大。解决办法是定期执行
VACUUM清理过期日志。 - 小文件问题:频繁的流式写入会产生大量小文件,影响查询性能。我建议设置
OPTIMIZE或COMPACT任务,定期合并小文件。 - Schema 演化冲突:多个任务同时修改表 Schema 可能导致冲突。最好统一管理 Schema 变更,避免并发操作。
- 版本回滚风险:时间旅行虽然方便,但回滚到旧版本会丢失之后的所有变更。回滚前一定要确认没有其他任务依赖当前版本。
一个小建议:刚开始用 Delta Lake 或 Iceberg 时,先在测试环境跑通所有操作流程。特别是事务日志的清理策略和文件合并策略,一定要根据数据量提前规划好。