为什么需要流处理
卷二结束时,eventd v2 是一个完整的响应式 HTTP 服务集群。它能处理高并发请求、保持响应式背压、在故障时自动恢复。但有一个根本局限:
所有操作都是「请求-响应」式的——用户必须先发起请求,系统才能返回结果。
这意味着:
- 实时监控需要前端不断轮询 API
- 异常检测依赖离线 batch job,延迟小时级
- 用户行为分析基于昨天的数据
流处理引擎改变这个模式:事件一发生,处理立即开始,结果在毫秒到秒级内可得。
批处理 vs 流处理
| 维度 | 批处理(Hadoop/Spark Batch) | 流处理(Flink/Kafka Streams) |
|---|---|---|
| 数据单位 | 有界数据集(文件/表) | 无界数据流(事件序列) |
| 处理触发 | 定时调度(每小时/每天) | 事件驱动(来一条处理一条) |
| 延迟 | 分钟到小时 | 毫秒到秒 |
| 容错 | 重跑整个 batch | Checkpoint 精确恢复 |
| 状态 | 无(或外部数据库) | 内置状态后端(RocksDB/Heap) |
| 适用 | 报表、离线分析 | 实时风控、实时监控、实时推荐 |
批处理问「过去一天发生了什么」。流处理问「这件事发生后的下一秒该做什么」。
有界流与无界流
Flink 统一了批和流:
无界流(Unbounded Stream)
→ 没有结束点
→ 如 Kafka Topic、Socket 流
→ 必须持续处理
有界流(Bounded Stream)
→ 有明确的开始和结束
→ 如 2026-11-05 0:00 到 23:59 的日志
→ 批处理是有界流的特例
Flink 的 DataStream API 处理无界流;DataSet API(已废弃)处理有界流。现代 Flink 用 Table API / SQL 统一两者。
本卷的边界
| 已有内容 | 本卷不写 | 本卷写什么 |
|---|---|---|
| 《Java 消息中间件·事件驱动架构》 | Kafka Producer/Consumer API、broker 运维、分区重分配 | Kafka Streams DSL 与拓扑编程 |
| 《Java 消息中间件·内核》 | Kafka 协议、日志存储、副本同步 | Kafka Streams 状态存储、Exactly-Once 语义 |
| Spark/Flink 运维书籍 | 集群部署、Yarn/K8s 调度、Checkpoint 后端存储 | Flink DataStream Java API 编程模型 |
| 流处理理论教材 | Watermark 数学证明、一致性模型形式化 | 代码实现、参数调优、故障排查 |
两条引擎路线
本卷同时介绍 Kafka Streams 和 Flink,它们是互补的:
| 引擎 | 优势 | 适用场景 |
|---|---|---|
| Kafka Streams | 轻量、无需集群、与 Kafka 深度集成 | 数据清洗、格式转换、简单聚合、微服务事件处理 |
| Flink | 精确一次、低延迟、复杂窗口/CEP、大规模 | 实时指标、风控规则、复杂事件模式、大数据量聚合 |
eventd v3 的架构:
eventd v2 事件 → Kafka Topic "eventd-raw"
→ Kafka Streams(清洗:去重、标准化、过滤异常)
→ Kafka Topic "eventd-cleaned"
→ Flink DataStream(窗口聚合:每分钟每用户统计)
→ Redis(实时指标缓存)
→ WebSocket/SSE(面板实时推送)
Kafka Streams 做「轻量级有状态转换」,Flink 做「复杂计算与窗口分析」。
贯穿项目:eventd v3
┌─ eventd-raw (Kafka Topic)
│ ↓ Kafka Streams 清洗管道
├─ eventd-cleaned (Kafka Topic)
│ ↓ Flink DataStream
├─ 实时指标 (Redis)
│ ↓ SSE/WebSocket
└─ 实时面板 (浏览器)
- 输入:eventd v2 产生的业务事件(订单创建、用户登录、库存变动)
- 清洗:Kafka Streams 去重、校验字段、标准化格式
- 聚合:Flink 按 1 分钟滚动窗口统计订单量、计算平均延迟、检测异常模式
- 输出:实时指标写入 Redis,面板通过 SSE 推送更新
如何阅读本卷
路径 A:顺序通读
- 第 1–3 章:流处理基础与 Kafka Streams 入门
- 第 4–8 章:Flink DataStream API 深入
- 第 9–12 章:eventd v3 完整实现
- 第 13–14 章:测试、性能与运维
路径 B:已有 Kafka 经验
跳过第 2–3 章(Kafka Streams 基础),从第 4 章(Flink)开始。第 9 章看 eventd v3 架构衔接。
路径 C:只想看代码
前言(环境)→ 第 9 章(eventd v3 架构)→ 附录 A(Flink 速查)→ 附录 B(Kafka Streams 速查)。
环境要求
| 组件 | 版本 |
|---|---|
| JDK | Temurin 17(与前言一致;不要用 25 运行 Flink 1.20) |
| Maven | 3.9.12 |
| Kafka | 3.8.1(单机或使用 kafka-streams-test-utils) |
| Flink | 1.20.x(Java DataStream API) |
| Redis | 7.x(面板缓存) |
Flink 开发使用 MiniCluster,不需要本地 Flink 集群。Kafka Streams 使用 TopologyTestDriver 单元测试,不依赖运行中的 Kafka broker。
一个提醒
流处理最大的陷阱不是「不会写窗口代码」,而是对时间语义理解错误。
// 危险:用处理时间处理事件时间数据
stream.assignTimestampsAndWatermarks(
WatermarkStrategy.<MyEvent>forBoundedOutOfOrderness(Duration.ofSeconds(5))
.withTimestampAssigner((event, timestamp) -> event.getProcessingTime()) // ❌ 错误!
);
应该用 event.getEventTime()——即业务发生的时间,而不是代码处理的时间。时间语义错误会导致窗口分配错误、乱序数据丢失、结果不可复现。
本卷的目标不是让你学会更多 API,而是让你在需要实时性时知道选什么引擎,在需要一致性时知道怎么配置 Checkpoint。
从流处理范式开始:第 1 章 Dataflow、窗口与时间语义 。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。