2. 实时数仓架构演进:Lambda架构、Kappa架构、流批一体,实时宽表在其中的定位
聊实时宽表之前,咱们得先搞清楚它到底活在什么样的架构里。我见过不少团队,一上来就撸SQL搞宽表,结果发现数据对不上、延迟降不下来、运维想骂人。说白了,架构没选对,后面全是坑。
这一节,我带大家捋一遍实时数仓架构的演进路线。你想想看,从Lambda到Kappa再到流批一体,每一步其实都是在解决上一代架构的痛点。而实时宽表,恰恰是这些架构里最核心的“数据载体”。
2.1 Lambda架构:批流分离的“双轨制”
Lambda架构是2011年左右由Nathan Marz提出的。它的核心思路很简单:用批处理保证数据的准确性,用流处理保证数据的低延迟。两条链路并行,最终在服务层合并。
核心思想:批处理层(Batch Layer)+ 流处理层(Speed Layer)+ 服务层(Serving Layer)
我在2016年参与过一个电商大促项目,用的就是Lambda架构。批处理跑Hive,凌晨算全量;流处理用Storm,实时算增量。结果呢?一到双十一,批处理和流处理的数据对不上,运维同学半夜打电话问我:“到底该信哪条链路?”
Lambda架构的典型流程是这样的:
- 批处理层:全量数据定期计算,生成不可变的离线视图。准确率高,但延迟大(小时级甚至天级)。
- 流处理层:实时数据增量计算,生成近似视图。延迟低(秒级),但可能丢数据或重复计算。
- 服务层:合并批视图和流视图,对外提供统一查询接口。
这个架构最大的问题,我总结为“两套代码、两套逻辑、两套运维”。批处理和流处理各写一套代码,逻辑还得保持一致。你想想看,一个简单的过滤条件改了,批和流都得改,稍不注意就出bug。
避坑指南:我曾经在一个项目中,批处理用Hive SQL,流处理用Flink SQL,两套代码的UDF实现细节不一样,导致同一个字段在批和流里算出来的值差了0.01%。排查了整整两天。所以,Lambda架构下,代码一致性是最大的隐性成本。
2.2 Kappa架构:流处理“一统天下”
既然Lambda架构这么麻烦,那能不能只用一套流处理搞定所有事情?2014年,Jay Kreps提出了Kappa架构。核心思想是:所有数据都走流处理,批处理只是流处理的一个特例——把历史数据重新回放一遍就行了。
说白了,Kappa架构就是“流处理打天下”。它只有一个处理层,数据从Kafka进来,经过流处理引擎(比如Flink),直接输出到服务层。如果需要重新计算历史数据,就把Kafka里的数据从头再消费一遍。
| 对比维度 | Lambda架构 | Kappa架构 |
|---|---|---|
| 处理层数 | 批处理 + 流处理(两套) | 流处理(一套) |
| 代码维护 | 两套代码,需保持逻辑一致 | 一套代码,逻辑统一 |
| 数据回溯 | 重新跑批处理 | 重新消费Kafka数据 |
| 运维复杂度 | 高(两套集群、两套监控) | 中(一套集群) |
| 适用场景 | 对准确性要求极高,且历史数据量大 | 实时性要求高,数据可重放 |
Kappa架构看起来很美,但实际落地时有个硬伤:Kafka的数据保留时间有限。我见过一个金融项目,业务要求回溯90天的数据做重算。Kafka集群的磁盘根本扛不住,最后只能妥协——把历史数据存到HDFS,回溯时再灌回Kafka。嗯,这其实又回到了Lambda的老路上。
我的建议:如果你的业务场景中,数据回溯窗口不超过7天,Kappa架构是首选。超过7天,建议考虑Kappa + 离线存储的混合方案,或者直接上流批一体。
2.3 流批一体:Lambda和Kappa的“终极融合”
流批一体,说白了就是“一套引擎、一套SQL、一套元数据”,同时支持流处理和批处理。Flink在1.12版本之后,正式实现了流批一体。你写一段SQL,既可以跑在流模式(实时),也可以跑在批模式(离线),逻辑完全一致。
为什么会这样?因为Flink把批处理看作“有界流”,流处理看作“无界流”。底层API统一了,上层语义自然就统一了。
我目前在主导的一个实时数仓项目,已经全面切换到流批一体架构。具体做法是:
- 数据源统一:所有业务数据先入Kafka,同时通过CDC工具同步到HDFS(作为离线备份)。
- 计算引擎统一:全部使用Flink SQL,流作业处理实时数据,批作业处理离线数据(本质上是同一个Flink集群的不同模式)。
- 元数据统一:使用Hive Metastore或Flink Catalog,流表和批表共用一套Schema。
- 存储统一:结果数据写入ClickHouse或HBase,流批共用。
这样做的好处很明显:开发效率翻倍,运维成本减半。但要注意,流批一体对集群资源的管理要求更高。我曾经遇到过流作业和批作业抢资源,导致实时延迟飙升。后来通过Flink的Resource Manager做了资源隔离,才算稳住。
2.4 实时宽表在架构中的定位
聊完架构演进,咱们回到实时宽表。不管你是Lambda、Kappa还是流批一体,最终对外提供查询服务的,一定是某种“宽表”。
实时宽表在架构中的定位,我总结为三个角色:
- 数据整合层:把多张事实表、维度表通过Join合并成一张大宽表,消除数据孤岛。
- 性能加速层:宽表预计算了关联关系,查询时不需要再Join,直接单表查询,性能提升几个数量级。
- 业务语义层:宽表的字段命名、类型定义贴近业务,前端应用直接使用,不需要理解底层数据模型。
在Lambda架构中,实时宽表通常由流处理层生成,离线宽表由批处理层生成,服务层再合并。在Kappa架构中,实时宽表就是唯一的宽表,历史数据通过重放Kafka重新生成。在流批一体架构中,实时宽表和离线宽表共用一套代码,只是运行模式不同。
核心观点:实时宽表不是某个架构的专属产物,而是所有实时数仓架构的“最终输出形态”。架构可以变,但宽表这个“数据载体”不会变。
下面这张图,展示了实时宽表在不同架构中的位置:
从这张图可以看得很清楚:Lambda架构下,实时宽表是“拼”出来的;Kappa架构下,实时宽表是“流”出来的;流批一体架构下,实时宽表是“一套代码跑出来的”。
我个人更倾向于流批一体架构。原因很简单:少维护一套代码,就少一半的bug。但如果你团队的技术栈还停留在Spark Streaming + Hive的阶段,Lambda架构也不是不能用。关键是要想清楚,你的业务到底需要多高的实时性,以及你愿意为数据一致性付出多少运维成本。
选型建议:
- 实时性要求秒级,且数据回溯窗口小(≤7天)→ Kappa架构
- 实时性要求秒级,但数据回溯窗口大(>7天)→ 流批一体架构
- 实时性要求分钟级,且已有成熟的批处理体系 → Lambda架构(但建议逐步向流批一体迁移)
嗯,架构选型这块,没有银弹。但有一点是确定的:实时宽表作为最终的数据输出形态,它的设计质量直接决定了查询性能的上限。接下来的章节,我会带大家深入实时宽表的Join策略、状态管理、数据一致性等核心问题。这些才是真正考验功力的地方。