1. 流批一体概述:为什么需要流批一体?

做大数据架构这些年,我见过太多团队在实时和离线两条线上来回折腾。说白了,流批一体不是技术噱头,是被业务逼出来的。今天咱们就从最根本的问题聊起——为什么我们需要流批一体?

1.1 传统架构的痛点:两条腿走路

先回忆一下传统做法。大多数公司早期都是这样:

  • 离线批处理:用 Hive/Spark 跑 T+1 报表,数据准,但慢。
  • 实时流处理:用 Storm/Flink 做秒级监控,数据快,但可能丢或重复。

两套系统,两套代码,两套运维。你想想看,同样的业务逻辑要在批和流里各写一遍,维护成本直接翻倍。我在一家电商公司就遇到过这种事——离线算的 GMV 和实时算的 GMV 差了 3 个点,两边开发互相甩锅,最后发现是窗口聚合逻辑没对齐。

核心矛盾:业务既想要实时的时效性,又想要离线的准确性。传统架构无法同时满足。

1.2 Lambda 架构:一个妥协的方案

为了解决这个问题,Nathan Marz 提出了 Lambda 架构。它的思路很简单——两条路都保留,最后合并结果。

Lambda 架构示意图 数据源 (Kafka) 批处理层 Hive/Spark (T+1) 流处理层 Flink/Storm (秒级) 服务层 (合并) 批结果 + 流结果 最终输出 ⚠ 两套代码,维护成本高 批流结果可能不一致

Lambda 架构分三层:

  • 批处理层:全量数据,保证准确性
  • 流处理层:增量数据,保证低延迟
  • 服务层:合并批和流的结果,对外提供服务

听起来挺合理对吧?但实际用起来问题不少。我曾经维护过一个 Lambda 架构的推荐系统,批处理用 Spark,流处理用 Flink。每次改特征逻辑,两边都得改,而且合并层经常出现时间窗口对不齐的情况。说白了,Lambda 架构只是把问题从「选批还是选流」变成了「怎么让批和流结果一致」。

避坑指南:我曾经见过一个团队在 Lambda 架构上跑了两年,最后发现服务层的合并逻辑比批和流加起来还复杂。如果你团队规模不大,Lambda 架构的维护成本可能会吃掉所有实时收益。

1.3 Kappa 架构:简化但不够完美

后来 Jay Kreps 提出了 Kappa 架构。它的核心思想是——只用一套流处理引擎,通过重放历史数据来达到批处理的效果。

Kappa 架构示意图 数据源 (Kafka) 流处理引擎 (Flink) 实时流 / 历史重放 最终输出 ✅ 一套代码,维护简单 ❌ 历史重放性能瓶颈

Kappa 架构的好处很明显:

  • 一套代码搞定批和流
  • 没有合并层的复杂度
  • 数据一致性更容易保证

但问题也来了——历史数据重放很慢。我做过一个测试,用 Flink 重放 30 天的 Kafka 数据,跑了将近 4 个小时。如果业务需要频繁回溯修正,Kappa 架构的时效性就扛不住了。

对比维度 Lambda 架构 Kappa 架构
代码维护 两套代码,维护成本高 一套代码,维护简单
数据准确性 批处理保证最终准确 依赖流处理语义保证
历史回溯 批处理天然支持 需要重放,性能瓶颈
资源消耗 两套集群,资源浪费 一套集群,资源节省
运维复杂度 高,需要协调批流结果 低,单一引擎运维

1.4 流批一体:取长补短

所以你看,Lambda 和 Kappa 各有各的短板。流批一体的思路就是——用一套引擎、一套代码、一套存储,同时支持实时和离线场景。

具体来说,流批一体要解决三个核心问题:

  1. 统一编程模型:批和流用同一套 API,同一个逻辑
  2. 统一存储:实时数据和离线数据共享同一份存储
  3. 统一调度:批任务和流任务在同一个调度体系下管理

我个人习惯把流批一体理解为「用流的方式处理实时数据,用批的方式保证数据质量」。说白了,实时数据先出,保证时效性;离线数据后补,保证准确性。两者最终要能对得上。

我的经验:流批一体不是要消灭批处理,而是让批处理成为流处理的「兜底机制」。实时数据出错了?没关系,离线回填会帮你修正。这才是流批一体的核心价值。

1.5 离线回填:流批一体的关键场景

离线回填,说白了就是用离线批处理来修正或补充实时流处理的结果。这是流批一体架构中最常见、也最实用的场景。

我举几个实际例子:

  • 电商大促:实时大屏展示 GMV,但数据可能因为网络延迟或系统抖动有偏差。第二天用离线任务回填修正,保证财报数据准确。
  • 广告计费:实时扣费要快,但可能因为点击去重不及时多扣了。离线回填做最终结算,多退少补。
  • 用户画像:实时标签更新快,但可能因为特征缺失不准确。离线回填用全量数据重新计算,覆盖实时结果。

离线回填的核心流程是这样的:

离线回填核心流程 实时流处理 离线批处理 统一存储层 回填修正 实时先出 → 离线后补 → 数据一致

这个流程里有个关键点——回填不能覆盖实时数据,而是要合并。我见过有人直接用离线结果覆盖实时表,结果实时查询的延迟从秒级变成了小时级。正确的做法是分层存储:实时层用高性能存储,离线层用低成本存储,回填时只修正有问题的部分。

避坑指南:我曾经在一个项目中,离线回填任务跑得太慢,导致实时数据被覆盖前已经被下游消费了。结果就是——实时数据不准,离线数据也没赶上。后来我们加了版本号和时间戳,才解决了这个问题。记住:回填要有版本控制,不能无脑覆盖。

1.6 本章小结

聊了这么多,其实核心就一句话:流批一体的本质,是用一套架构同时满足实时和离线的需求,而离线回填是落地这个架构最关键的场景。

后面的章节,我会带你一步步实现一个完整的离线回填系统。从技术选型到代码实现,从性能优化到线上运维,咱们一个一个来啃。