2. 数据流模型与架构:从DAG到Lambda与Kappa
聊到流处理,绕不开一个核心问题:数据到底怎么流?
我见过不少团队,一上来就选框架、调参数,结果架构搭到一半发现数据路径是乱的。说白了,你连数据怎么走都没想清楚,优化吞吐就是空谈。这一章,我们就把数据流模型和主流架构掰开揉碎讲清楚。
2.1 数据流图:先画清楚数据怎么走
数据流图(Data Flow Diagram)是架构师的第一张草图。它不关心你用Kafka还是Pulsar,只关心:数据从哪来、经过什么处理、最终去哪。
我个人习惯,设计任何流处理系统前,先画一张三级数据流图:
- 一级(上下文图):只画外部系统、流处理核心、输出目标。比如:传感器 → 流处理引擎 → 数据库。
- 二级(处理图):拆出主要处理节点。比如:数据接入 → 清洗 → 聚合 → 窗口计算 → 输出。
- 三级(详细图):细化到每个算子的输入输出、状态存储、容错机制。
举个例子,一个简单的IoT数据流:
数据源(MQTT Broker)
↓
接入层(Kafka Connect / Flume)
↓
清洗算子(过滤无效数据、格式标准化)
↓
窗口聚合(每5秒计算一次均值)
↓
结果输出(写入InfluxDB + 触发告警)
嗯,这里要注意:数据流图上的每个箭头,背后都对应着网络开销、序列化开销、背压传播路径。箭头画得越乱,系统越难优化。
2.2 有向无环图(DAG):流处理的骨架
有向无环图(DAG)是流处理引擎的底层抽象。Flink、Spark Streaming、Kafka Streams,底层都是DAG。
为什么必须是DAG?因为不能有环。一旦出现环,数据就会无限循环,系统直接崩溃。你想想看,一个算子输出又回到自己输入,这不就是死循环吗?
DAG里有几个关键概念:
- 顶点(Vertex):一个处理算子,比如map、filter、window。
- 边(Edge):数据流动的方向,可以是one-to-one、redistribute、broadcast。
- 分区(Partition):数据在顶点间的切分方式,直接影响并行度。
我曾经在一个项目中,因为没注意边的类型,导致数据倾斜严重。一个简单的keyBy操作,默认是hash分区,结果某个key的数据量是其他key的100倍。那台机器的CPU直接打满,其他机器闲着。后来改成自定义分区器才解决。
下面这张图展示了典型的流处理DAG结构:
2.3 Lambda架构:批流分离的经典方案
Lambda架构是Nathan Marz提出的。核心思想很简单:用两条路处理数据。
- 批处理层(Batch Layer):处理全量历史数据,生成精确结果。延迟高,但准确。
- 流处理层(Speed Layer):处理实时增量数据,提供低延迟的近似结果。
- 服务层(Serving Layer):合并批处理和流处理的结果,对外提供查询。
我早期做实时数仓时,用的就是Lambda架构。批处理用Spark SQL跑T+1的全量聚合,流处理用Flink做秒级实时指标。听起来很完美,对吧?
但实际维护起来,问题不少:
- 两套代码:批处理和流处理逻辑要写两遍,维护成本翻倍。
- 结果合并复杂:批处理和流处理的结果可能不一致,需要额外的合并逻辑。
- 数据口径对齐难:批处理用T+1的数据,流处理用实时数据,口径经常对不上。
我记得有一次,批处理跑出来的日活是100万,流处理实时显示的是95万。业务方问为什么差5万?排查了两天才发现,流处理层丢了一部分晚到数据。这种问题在Lambda架构里太常见了。
2.4 Kappa架构:简化,再简化
Kappa架构是Jay Kreps提出的。他当时在LinkedIn做Kafka,觉得Lambda太复杂了,干脆只用一条流处理链路。
核心思想:所有数据都当作流来处理。历史数据重放时,从Kafka的起始偏移量开始消费,重新计算一遍。
| 对比维度 | Lambda架构 | Kappa架构 |
|---|---|---|
| 处理链路 | 批处理 + 流处理 | 仅流处理 |
| 代码维护 | 两套代码 | 一套代码 |
| 历史重算 | 批处理层负责 | 流处理重放Kafka |
| 延迟 | 批处理高,流处理低 | 统一低延迟 |
| 复杂度 | 高 | 中 |
| 适用场景 | 对历史数据精确性要求极高 | 实时性要求高,可接受最终一致性 |
你可能会问:Kappa架构是不是万能的?当然不是。它有个前提:你的消息队列(比如Kafka)必须能保存足够长时间的历史数据。如果数据量太大,Kafka的存储成本会很高。
2.5 如何选择?我的决策框架
说了这么多,到底怎么选?我总结了一个简单的决策框架:
- 数据量级:日均数据量超过10TB,优先考虑Lambda,因为纯流处理的状态存储压力太大。
- 延迟要求:秒级延迟必须Kappa;分钟级延迟Lambda也能接受。
- 精确性要求:需要精确一次语义且历史数据不能丢,Lambda更成熟。
- 团队能力:团队熟悉Flink/Spark Streaming,Kappa上手更快;团队有Hive/Spark SQL经验,Lambda更顺手。
- 运维成本:Kafka集群维护成本低于Hadoop + Kafka两套集群。
嗯,这里要提醒一句:架构选型没有银弹。我见过用Kappa架构做金融对账的,结果数据不一致被审计打回来。也见过用Lambda架构做实时推荐的,批处理还没跑完,推荐结果已经过时了。关键还是看业务场景。
最后,无论选哪种架构,DAG的设计都是基础。把数据流图画清楚,把DAG的边类型选对,把分区策略调好——这些基本功做到位了,架构选型只是锦上添花。