1. 流处理基础:从一次“差点背锅”的经历说起

我记得刚接手第一个流处理项目时,领导问我:“这个实时指标到底准不准?”我拍着胸脯说没问题。结果上线第一天,数据对不上——批处理跑出来 100 万条,流处理只出了 98 万。排查了一整夜,最后发现是 checkpoint 间隔设得太长,任务挂了之后回放丢了一段窗口数据。

从那以后,我养成了一个习惯:先搞清楚流处理到底在做什么,再动手写代码。这一章,我们就从最基础的概念开始聊。

1.1 什么是流处理

流处理,说白了就是数据一边来,一边算。你想想看,传统做法是把数据攒起来,等攒够了再统一处理——这叫批处理。但很多场景等不了:

  • 用户刚点了一下“下单”,你得立刻检查库存
  • 服务器 CPU 飙到 90%,你得马上告警
  • 直播间弹幕刷屏,你得实时算出热度趋势

这些场景的共同点是:数据是连续不断的,延迟必须控制在秒级甚至毫秒级。流处理就是为这种场景设计的计算模型。

核心特征:

  • 数据无界(unbounded)——你不知道什么时候结束
  • 处理低延迟——通常 < 1 秒
  • 状态持续——需要记住中间结果
  • 结果即时——每来一条数据都可能触发输出

1.2 流处理 vs 批处理:不只是“快”和“慢”的区别

很多人觉得流处理就是“快一点的批处理”。嗯,这个理解其实有点危险。我在项目中见过不少团队,把批处理的逻辑直接搬到流上,结果窗口算不对、状态炸了、数据还乱序。

两者的本质区别,我列个表你就清楚了:

维度 批处理 流处理
数据范围 有界(已知开始和结束) 无界(持续到达)
触发时机 手动或定时触发 数据到达即触发
延迟要求 分钟~小时级 毫秒~秒级
容错方式 重跑整个批次 状态快照 + 精确一次语义
典型框架 MapReduce, Spark (batch) Flink, Kafka Streams

这里有个关键点:流处理不是批处理的子集,而是另一种计算范式。批处理假设数据是静止的,你可以反复扫描;流处理假设数据是流动的,你只有一次机会(或者有限次重放)来处理它。

我曾经踩过的坑: 把批处理的“全量聚合”逻辑直接搬到流上。比如统计一天的总销售额,批处理可以等 24 点后一次性 sum。流处理如果也这么干,每来一条数据就全量重算一次,状态会越积越大,最后 OOM。正确的做法是用增量聚合 + 窗口触发。

1.3 常见流处理框架对比

现在主流的流处理框架有三个:Flink、Spark Streaming、Kafka Streams。我三个都用过,说说我的真实感受。

1.3.1 Apache Flink

Flink 是目前公认的流处理标杆。它的核心设计就是“一切皆流”——批处理只是流的一个特例(有界流)。

  • 优势: 真正的逐条处理、精确一次语义、强大的状态管理、事件时间语义成熟
  • 劣势: 学习曲线陡、部署运维复杂、资源消耗相对高
  • 适用场景: 对延迟和准确性要求极高的核心业务(金融交易、实时风控、复杂事件处理)

1.3.2 Spark Streaming

Spark Streaming 本质上是微批处理——把流切成一个个小批次,然后用 Spark 引擎去跑。我早期做流处理时用的就是它。

  • 优势: 生态丰富(和 Spark SQL/MLlib 无缝集成)、社区成熟、部署简单
  • 劣势: 延迟受批次间隔限制(通常几百毫秒到几秒)、状态管理不如 Flink 灵活
  • 适用场景: 对延迟要求不那么苛刻、但需要和批处理/机器学习任务混跑的场景

1.3.3 Kafka Streams

Kafka Streams 是一个轻量级库,不是完整的计算框架。它直接跑在你的应用进程里,不需要单独部署集群。

  • 优势: 极简部署、与 Kafka 深度集成、延迟低、适合做微服务内的流处理
  • 劣势: 功能相对有限、不适合复杂 DAG、状态管理依赖 RocksDB(有性能瓶颈)
  • 适用场景: 简单的 ETL、数据管道、实时聚合(比如统计每分钟的 PV/UV)

我的选型建议: 如果你需要做复杂的窗口计算、事件时间处理、精确一次语义,直接上 Flink。如果团队已经用了 Spark 生态,且延迟容忍度在秒级,Spark Streaming 够用。如果只是做轻量级的数据管道,Kafka Streams 最省心。

1.4 核心概念速览

在进入监控和问题排查之前,有几个概念你必须先理解。我挑三个最重要的说:

  1. 事件时间 vs 处理时间: 事件时间是数据实际发生的时间,处理时间是数据到达系统的时间。流处理里,事件时间才是“真”时间。我见过太多因为用处理时间做窗口导致数据不准的案例。
  2. 状态(State): 流处理是有状态的。比如统计过去 5 分钟的点击量,你得记住这 5 分钟内的所有点击。状态管理的好坏,直接决定了任务的稳定性和容错能力。
  3. 精确一次语义(Exactly-Once): 数据既不丢也不重。这是流处理最难保证的特性。Flink 通过 checkpoint + 两阶段提交实现了这一点,但代价是性能开销。

1.5 本章知识体系

下面这张图概括了本章的核心逻辑,你可以把它当作后续学习的“地图”:

流处理基础知识体系 流处理基础 什么是流处理 数据无界 低延迟 状态持续 即时输出 流 vs 批处理 有界 vs 无界 触发方式 容错差异 延迟要求 框架对比 Flink Spark Streaming Kafka Streams 理解这三块内容,是后续学习监控和问题排查的基础

1.6 小结

这一章我们聊了流处理的核心概念、与批处理的本质区别,以及三个主流框架的选型思路。你可能觉得这些内容偏理论,但我想说:基础不牢,排查问题的时候会非常痛苦。我见过太多人因为搞不清事件时间和处理时间的区别,花了一周时间查一个窗口不准的 bug。