1. 批处理与流处理的分水岭:为什么实时场景不能只堆机器
1.1 传统数仓里的“定时跑批”思维
我刚入行大数据时,大部分数据处理任务都长一个样:凌晨定个调度,把前一天积累的日志从上游拉下来,清洗、关联、聚合,再写进数仓,第二天上班看报表。这套T+1模式背后是批处理思想——数据被切成一个个“批次”,按固定节奏批量处理,最典型的就是MapReduce和早期Hive SQL。
批处理的优点是逻辑简单、容错直接:一批跑挂了,重跑这一批就行。但它有一个天然缺陷:结果永远滞后。业务方想要“今天实时的GMV”“当前在线的用户数”“刚发生的异常交易”,批处理给不了。
你可能觉得,那把调度周期从每天改成每小时、每分钟,甚至在内存里做微批,不就能接近实时了吗?这确实是一部分演进路线,但问题在于,单纯缩短批次间隔会带来新的开销:调度延迟、任务启动开销、数据边界切分成本都会放大。更重要的是,很多需求本质上不是“尽快把一批算完”,而是“数据到了就要立刻算”,计算要跟着连续的事件流走,而不是跟着固定节奏触发。
1.2 事件时间与处理时间:流处理必须先解决的认知问题
数据流处理的核心,是把计算模型从“按批切分”改成“按事件流动”。这听起来简单,做起来却绕不开一个根本问题:你按什么时间来计算?
举个例子,用户在上午10点59分下单,但这条日志因为网络抖动,直到11点01分才到达处理系统。如果以“处理时间”为标准,这笔订单会被归入11点的统计;如果以“事件时间”为标准,它应该归入10点的统计。对大多数业务来说,事件时间才是真实发生的时间,处理时间只是系统收到数据的时间。
批处理可以天然回避这个问题,因为一批数据在调度前就已经在那里,你选择“按某个业务字段的时间”聚合就行。但在流处理里,数据是无穷无尽的,你永远不知道某个时间点的数据是否已经全部到达。为了处理这种不确定性,才引入了水位线(Watermark)机制,这是后话,但理解事件时间和处理时间的差异,是进入流处理世界的第一个门槛。
1.3 延迟、吞吐、一致性:三个只能权衡不能全占的指标
做流处理方案时,经常被问:“能不能做到毫秒级延迟,还要每秒处理百万条,同时保证一条不重不漏?”这个问题本身就是外行问的。分布式系统里,延迟、吞吐和一致性永远在互相挤占。
- 延迟低,意味着每次处理的数据量少、同步确认频繁,吞吐必然受限制;
- 吞吐高,意味着批量攒数据、批量发送,延迟必然上升;
- 一致性要求高,意味着需要分布式快照、两阶段提交之类的开销,延迟和吞吐都会受影响。
真正成熟的做法,是按业务场景做取舍。比如风控反欺诈要求秒级甚至毫秒级响应,可以接受少量乱序和重复;离线报表可以忍受分钟级延迟,但要求数据准确完整;实时大屏更看重吞吐和低延迟,丢几条告警可以接受。
1.4 从Lambda架构到Kappa架构:流处理走上舞台中心
早期为了兼顾实时性和准确性,业界流行Lambda架构:一套离线批处理链路负责最终准确数据,一套实时流处理链路负责低延迟结果,最后在服务层合并。这个架构能跑,但维护成本极高——同一套统计逻辑要在两套引擎里各写一遍,口径稍微对不上,结果就对不上。
后来大家逐渐意识到,如果把流处理引擎的“重放”(Replay)能力用好,让流引擎从最早的事件开始消费,就能把历史的批量数据也当作一条无穷流重新计算一遍,这就是Kappa架构的思路。Kappa架构把逻辑收敛到一套流处理代码上,既处理实时增量,也通过重放处理历史数据,逻辑统一、运维简单。这也是为什么现在大数据领域聊分布式计算,重心越来越偏向数据流处理。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 数据流引擎的底层执行逻辑:算子、分区与时钟对齐
2.1 从逻辑图到物理执行图:算子是怎么被拆开的
不管用Flink、Spark Streaming还是Kafka Streams,写出来的程序最终都会形成一个计算逻辑图(DAG)。比如一个典型任务:从Kafka读数据,做清洗,按用户ID分组,开一小时窗口聚合,再写回Kafka。你写的每一步转换,对应图里的一个节点。
真正分布式执行时,引擎不会老老实实按一个并行度跑整个图,而是把每个节点拆成多个并行子任务。比如Source节点并行度是3,也就是3个线程分别消费Kafka的3个分区;窗口聚合
