一、数据湖的起源与演进:从数据仓库到数据湖,再到湖仓一体
聊增量计算之前,咱们得先搞清楚一个问题——数据湖到底是怎么来的?
我入行那会儿,正是数据仓库如日中天的年代。那时候大家做报表、跑BI,全靠ETL把数据洗得干干净净,再塞进星型模型里。听起来挺完美,对吧?但干过的人都知道,这玩意儿有个硬伤:数据进来之前,你就得把Schema定好。业务一变,模型就得跟着改,改一次折腾半个月。
1.1 数据仓库的黄金时代与隐痛
数据仓库的核心思想是「Schema on Write」——写入时定义结构。好处是查询快,坏处是灵活差。
典型数据仓库架构的特征:
- 强Schema约束,写入前必须建模
- 以SQL为核心,面向结构化数据
- 存储成本高,扩展性有限
- ETL流程复杂,变更代价大
我记得2014年在一个金融客户那里做项目,他们的数据仓库里光一个客户维度表就改了17次结构。每次改完,下游的ETL作业全得重跑,运维同学都快疯了。说白了,传统数仓适合「已知的已知」,但面对「未知的未知」就力不从心了。
1.2 数据湖的诞生:反其道而行之
2010年左右,Hadoop生态开始成熟。大家发现,与其先建模再存数据,不如先把原始数据扔进去,需要的时候再解析。这就是「Schema on Read」——读取时定义结构。
数据湖的核心承诺很简单:存得住、算得动、随便来。结构化、半结构化、非结构化数据,一股脑往里塞。我2016年帮一家电商公司搭数据湖时,他们每天要接入200+种日志格式,要是用传统数仓,光建模就得干半年。数据湖模式下,先存再说,后面慢慢梳理。
数据湖 vs 数据仓库 核心差异:
| 维度 | 数据仓库 | 数据湖 |
|---|---|---|
| Schema策略 | 写入时定义(Schema on Write) | 读取时定义(Schema on Read) |
| 数据类型 | 结构化为主 | 结构化+半结构化+非结构化 |
| 存储成本 | 较高(需要预处理) | 较低(原始存储) |
| 数据质量 | 高(ETL清洗后) | 低到中(原始数据) |
| 变更灵活性 | 低 | 高 |
1.3 数据湖的「沼泽化」困境
理想很丰满,现实很骨感。数据湖很快暴露了问题——没有治理的数据湖,最后都会变成数据沼泽。
我见过太多案例了。数据往里堆,没人管格式、没人管质量、没人管生命周期。结果呢?想用数据的时候,发现根本不知道哪些数据是干净的,哪些是垃圾。更麻烦的是,数据湖不支持ACID事务,你写一半任务挂了,数据可能就残了。
为什么会这样?因为数据湖的底层存储(比如HDFS、S3)本身不支持文件级的事务和一致性语义。你跑一个批处理任务,写到一半失败了,留下的半成品文件没人清理。下次读数据的人,可能读到的是残缺的数据集。
我曾经踩过的坑:有一次在数据湖上跑一个全量重刷任务,跑了6个小时后集群OOM了。结果发现目标表里混着新旧两版数据,下游报表直接对不上数。从那以后,我坚持所有数据湖写入操作必须带「原子性标记」——要么全成功,要么全回滚。
1.4 湖仓一体:取长补短的进化
既然数据仓库太死板,数据湖太混乱,那能不能把两者的优点结合起来?这就是湖仓一体(Lakehouse)的出发点。
湖仓一体的核心思路是:用数据湖做存储底座,把数据仓库的事务、索引、SQL能力搬上来。像Delta Lake、Apache Iceberg、Apache Hudi这些技术,本质上就是在数据湖上加了事务层和元数据层。
我2019年开始接触Delta Lake,第一次看到它支持ACID事务时,说实话挺震撼的。你想想看,在S3上做事务,这以前谁敢想?
-- Delta Lake 示例:事务性写入
INSERT INTO events
SELECT * FROM raw_events
WHERE dt = '2024-01-15'
-- 如果失败,自动回滚,不会留下脏数据
湖仓一体带来的关键能力包括:
- ACID事务:并发读写不冲突,失败自动回滚
- Schema演进:支持字段增删改,不影响历史数据
- 时间旅行:可以查询任意历史版本的数据
- 统一存储:一份数据,同时支持BI分析和机器学习
1.5 为什么增量计算成了刚需?
好,前面铺垫了这么多,终于到核心问题了——为什么增量计算在湖仓一体时代成了刚需?
原因有三点,我一个个说。
第一,数据规模变了。以前数仓里跑的是GB级数据,全量重刷还能接受。现在数据湖里动不动就PB级,你每天全量跑一次?存储和计算成本都扛不住。我见过一个客户,每天全量跑一次订单表,光存储开销就占了预算的40%。改成增量后,直接降到5%。
第二,时效性要求变了。实时报表、实时风控、实时推荐——业务方要的是分钟级甚至秒级的数据。全量批处理跑一次要几小时,黄花菜都凉了。增量计算可以做到「数据一到就处理」,延迟大幅降低。
第三,湖仓一体的技术底座成熟了。以前做增量计算,难点在于「怎么保证增量数据不丢不重」。传统数据湖没有事务支持,增量处理很容易出问题。现在Delta Lake、Iceberg这些技术提供了Change Data Feed、增量查询等能力,让增量计算有了可靠的基础。
增量计算的核心价值:
- 降低存储成本:只处理变化的数据,避免全量冗余
- 降低计算成本:减少重复计算,提升资源利用率
- 提升时效性:从T+1走向近实时
- 支持流批一体:同一套逻辑,批处理和流处理都能跑
下面这张图展示了从数据仓库到湖仓一体的演进脉络,以及增量计算在其中扮演的角色:
1.6 增量计算的技术基础:CDC与增量查询
增量计算要落地,离不开两个关键技术:CDC(Change Data Capture)和增量查询。
CDC负责捕获数据的变化。常见的手段有:
- 数据库日志解析(如Debezium读取MySQL binlog)
- 时间戳对比(通过last_modified字段识别变化)
- 触发器/审计表(数据库层面记录变更)
- 应用层双写(业务代码同时写主库和消息队列)
增量查询则是在湖仓引擎层面,只读取变化的数据。以Apache Iceberg为例:
-- Iceberg 增量查询:只读取指定时间范围内的变更
SELECT * FROM orders
FOR SYSTEM_VERSION AS OF '2024-01-15 10:00:00'
WHERE _change_type IN ('INSERT', 'UPDATE', 'DELETE')
AND _committed_at BETWEEN '2024-01-15 09:00:00' AND '2024-01-15 10:00:00'
我个人习惯把增量计算分为三个层次:
- 存储层增量:文件级别的增量写入,避免全量覆盖
- 计算层增量:只处理变化的分区或文件,不做全表扫描
- 应用层增量:业务逻辑只关注新增/变更的数据,不重算历史
避坑指南:我曾经在一个项目中,CDC采集的binlog数据直接写入数据湖,结果发现源库的一次DDL操作(加字段)导致下游所有增量任务报错。后来我养成了一个习惯——所有CDC管道必须做Schema兼容性校验,不兼容的变更要自动告警并暂停写入。
1.7 小结:增量计算不是可选项,是必选项
从数据仓库到数据湖,再到湖仓一体,这条演进路线背后有一个清晰的逻辑:数据架构越来越灵活,但灵活的前提是可控。增量计算就是那个「可控」的关键——它让你既能享受数据湖的低成本存储,又能获得数据仓库的事务保障。
接下来的章节,我会深入讲解增量计算在数据湖中的具体实现技术,包括Delta Lake的增量读写、Iceberg的增量查询优化、以及流批一体架构的设计模式。这些内容都是我这些年摸爬滚打总结出来的实战经验,希望能帮你少走弯路。