1. 数仓架构演进:从传统数仓到Lambda架构,再到Kappa架构的演变历程与核心痛点
聊数仓架构演进,其实就是在聊一个核心问题:数据到底要等多长时间才能用?
我入行那会儿,跑一个离线ETL任务,凌晨两点调度,早上九点出报表,业务方已经觉得很满意了。后来业务越来越卷,老板早上九点要看昨天的数据?不行,得看实时的。于是架构就开始变了。
这一章,咱们就捋一捋这条演进路线——从传统数仓到Lambda,再到Kappa,看看每一步到底解决了什么问题,又留下了什么坑。
1.1 传统数仓:T+1的“慢工出细活”
传统数仓的核心模式,说白了就是T+1。今天的数据,明天才能用。
架构上通常长这样:
- ODS层:原始数据落地,不做任何加工
- DWD层:数据清洗、去重、标准化
- DWS层:轻度汇总,按主题组织
- ADS层:面向业务应用的数据集市
数据流是单向的、批量的。每天晚上跑一堆Sqoop、Spark或Hive任务,把业务库的数据拉过来,一层一层往下刷。
核心特征:
- 数据延迟:24小时起步
- 计算模式:批量调度
- 存储介质:HDFS为主
- 一致性:强,因为都是全量或增量快照
我在项目中遇到过一件事:业务方早上八点冲进来说“昨天的转化率不对,能不能重跑一下?”我说行,改个参数重新调度,中午之前能出来。他叹了口气说“中午出来,老板已经开完晨会了。”——这就是T+1的痛。
个人习惯:传统数仓适合财务对账、月度报表这类“晚一天没关系”的场景。但千万别用它做实时风控或大屏监控,会出事的。
1.2 Lambda架构:批流“两条腿走路”
为了解决延迟问题,Nathan Marz在2011年提出了Lambda架构。它的思路很直接:批处理保证全量准确,流处理保证低延迟。
架构上分三层:
| 层级 | 职责 | 技术选型(典型) | 延迟 |
|---|---|---|---|
| Batch Layer | 全量数据计算,生成不可变的Master Dataset | Hadoop/Spark | 小时级 |
| Speed Layer | 实时增量计算,补偿Batch Layer的延迟 | Storm/Flink | 秒级 |
| Serving Layer | 合并Batch和Speed的结果,对外提供服务 | HBase/Redis | 准实时 |
听起来很完美对吧?但实际落地的时候,坑比想象的多。
我曾经踩过的坑:
- 两套代码,两套逻辑:批处理用Spark SQL写一套,流处理用Flink SQL再写一套。业务逻辑稍微复杂点,两边对不齐,结果不一样。排查起来,批说流算错了,流说批算错了,最后发现是窗口边界定义不一致。
- 数据合并的“最后一公里”:Serving Layer要同时读批和流的结果,然后做merge。如果批处理还没跑完,流数据已经更新了好几轮,合并逻辑写起来非常痛苦。
- 运维成本翻倍:两套集群、两套监控、两套告警。出问题的时候,你得同时懂批和流,不然根本定位不了。
我记得有一次做实时大屏,Speed Layer用Flink算PV/UV,Batch Layer用Spark算历史对比。上线第二天,大屏上的“今日累计”和“昨日同期”对不上,差了3%。排查了两天,最后发现是批处理那边的去重逻辑用了Bloom Filter,流处理这边用了HyperLogLog——两个近似算法,精度不一样。你说这找谁说理去?
1.3 Kappa架构:流处理“一统天下”
Lambda架构的痛点太明显了。Jay Kreps在2014年提出了Kappa架构,核心思想就一句话:为什么不能只用一套流引擎搞定所有事?
Kappa架构的思路是:
- 所有数据都当作流来处理
- 历史数据重算,通过重新消费Kafka中的日志来实现
- 不再区分Batch和Speed,只有一套Streaming Job
架构简化成两层:
- 消息队列层:Kafka,作为数据的“单一事实来源”
- 流处理层:Flink/Kafka Streams,负责所有计算逻辑
需要重算历史数据时,只需要把Kafka的offset重置到最早位置,重新跑一遍流任务就行。
Kappa架构的优势:
- 一套代码,一套逻辑,不存在批流不一致的问题
- 运维简单,只需要维护流处理集群
- 数据延迟可控,全链路秒级
但别急着欢呼,Kappa也不是银弹。我在实际项目中遇到过几个棘手的问题:
Kappa架构的“暗面”:
- 状态管理复杂:流处理是有状态的。如果任务挂了,重启后状态恢复是个大问题。Flink的Checkpoint/Savepoint机制虽然能解决,但配置不好容易OOM。
- 历史数据重算效率低:Kafka里存了几个月的日志,要重算一遍,得从头消费到尾。数据量大的时候,重算一次可能要跑好几天。
- Kafka存储成本高:为了支持重算,Kafka的日志保留时间得设得很长。TB级的数据存几个月,磁盘成本不是开玩笑的。
- 批处理场景不友好:有些场景天然适合批处理,比如复杂的多表Join、全量数据扫描。硬要用流处理来实现,代码写起来很别扭,性能也不一定好。
说白了,Kappa架构更适合数据链路简单、状态不大、重算频率低的场景。如果你要处理几百张表的复杂ETL,还是老老实实用Lambda或者混合架构吧。
1.4 三种架构的对比与选型建议
我整理了一张对比表,方便你快速决策:
| 维度 | 传统数仓 | Lambda架构 | Kappa架构 |
|---|---|---|---|
| 数据延迟 | T+1 | 秒级+小时级 | 秒级 |
| 开发成本 | 低 | 高(两套代码) | 中 |
| 运维成本 | 低 | 高 | 中 |
| 数据一致性 | 强 | 最终一致(需合并) | 最终一致 |
| 历史重算 | 容易 | 复杂 | 中等(依赖Kafka) |
| 适用场景 | 报表、财务对账 | 实时大屏+离线报表 | 实时数仓、监控 |
我的选型建议:
- 如果业务对实时性要求不高,传统数仓依然是最稳的选择
- 如果既要实时又要离线,Lambda架构是“标准答案”,但要做好两套代码对齐的规范
- 如果数据链路简单、团队规模小,Kappa架构能大幅降低运维成本
- 如果预算充足、团队能力强,可以考虑“Lambda+Kappa”混合架构——核心链路用Kappa,复杂ETL用Lambda
1.5 架构演进的核心逻辑(SVG图)
下面这张图,把三种架构的演进关系和核心痛点串起来了。你一看就明白:
嗯,看到这里你应该明白了。架构演进不是“新的一定比旧的好”,而是业务需求倒逼技术升级。传统数仓稳,但慢;Lambda全,但重;Kappa快,但有新坑。
我个人习惯是:先搞清楚业务到底要什么,再选架构。别为了追新而追新,也别因为怕麻烦而固步自封。后面几章,咱们会深入聊Lambda和Kappa的具体实现细节,包括Flink SQL怎么写、Kafka怎么配、状态怎么管理——到时候你就知道,这些坑其实都有办法填。