环境准备
必须版本
| 组件 | 版本 | 说明 |
|---|---|---|
| JDK | 17 | Flink 1.20 支持 Java 11/17;本书统一用 17 |
| Maven | 3.9.12 | 标准构建 |
| Kafka Streams | 3.8.1 | 流处理 DSL |
| Flink | 1.20.x | Java DataStream API |
| Redis | 7.x | 面板实时缓存 |
| Docker | 29.x(可选) | 本地启动 Kafka/Redis |
不要用 JDK 25 运行 Flink 1.20:该版本的支持矩阵只有 Java 11 和 17。
校验环境(实测)
下面的版本来自实际命令输出,不是目标配置:
macOS 26.3 (25D125), Apple Silicon
默认 JDK: Zulu 8.92.0.21 (1.8.0_482)
备用 JDK: Homebrew OpenJDK 27.0.1.0.3
Maven: 3.9.12(Maven 自身运行在默认 JDK 8 上)
Docker: 29.7.2
mvn -v 显示的 Java version 取决于 JAVA_HOME。构建本书工程前先安装并切换到 JDK 17:
export JAVA_HOME=$(/usr/libexec/java_home -v 17)
java -version # 应为 17.x
mvn -v # Java version: 17.x
说明:作者机器未安装 JDK 17,书中的代码片段只用 JDK 27 的 javac 做过部分语法核对,未做 Flink 运行时验收;验收类数字必须由读者在目标环境生成(见 12.3)。
Maven BOM
eventd-v3/pom.xml 的依赖管理:
<properties>
<maven.compiler.release>17</maven.compiler.release>
<kafka.version>3.8.1</kafka.version>
<flink.version>1.20.0</flink.version>
</properties>
<dependencies>
<!-- Kafka Streams -->
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-streams</artifactId>
<version>${kafka.version}</version>
</dependency>
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-streams-test-utils</artifactId>
<version>${kafka.version}</version>
<scope>test</scope>
</dependency>
<!-- Flink -->
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-streaming-java</artifactId>
<version>${flink.version}</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-clients</artifactId>
<version>${flink.version}</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-connector-kafka</artifactId>
<version>3.3.0-1.20</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-cep</artifactId>
<version>${flink.version}</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-statebackend-rocksdb</artifactId>
<version>${flink.version}</version>
</dependency>
<!-- 测试用 MiniCluster -->
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-test-utils</artifactId>
<version>${flink.version}</version>
<scope>test</scope>
</dependency>
<!-- Redis -->
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>6.5.1.RELEASE</version>
</dependency>
</dependencies>
注意 Flink Connector 版本:3.3.0-1.20 表示 connector 3.3.0 适配 Flink 1.20。
贯穿项目:eventd v3
eventd v3 接收 eventd v2 产生的事件流,实时清洗、聚合、展示。
数据流
eventd v2 (WebFlux + R2DBC)
└── 业务事件 → Kafka Producer → Topic "eventd-raw"
↓
Kafka Streams (清洗管道)
├── 去重(基于事件 ID)
├── 格式标准化(统一字段名、类型转换)
├── 异常过滤(丢弃非法数据)
└── 写入 Topic "eventd-cleaned"
↓
Flink DataStream (实时计算)
├── 滚动窗口:每分钟订单量
├── 滑动窗口:近 5 分钟平均延迟
├── CEP:连续 3 次失败告警
└── 结果写入 Redis
↓
实时面板 (SSE/WebSocket)
└── 浏览器实时刷新
模块划分
eventd-v3/
├── eventd-cleansing # Kafka Streams 清洗管道
│ └── 拓扑定义、自定义 Processor、状态存储配置
├── eventd-analytics # Flink DataStream 实时计算
│ ├── 窗口聚合作业
│ ├── CEP 规则引擎
│ └── 自定义 Source/Sink
├── eventd-panel # 实时面板(WebFlux SSE)
│ └── 读取 Redis、推送到客户端
└── eventd-shared # 共享事件模型、序列化器
测试环境
Kafka Streams:TopologyTestDriver
不需要运行 Kafka broker:
Properties props = new Properties();
props.put(StreamsConfig.APPLICATION_ID_CONFIG, "test-app");
props.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "dummy:9092");
Topology topology = buildTopology();
TopologyTestDriver driver = new TopologyTestDriver(topology, props);
// 发送测试数据
TestInputTopic<String, String> input = driver.createInputTopic(
"eventd-raw", new StringSerializer(), new StringSerializer());
input.pipeInput("key1", "{\"eventId\":\"1\",\"type\":\"order\"}");
// 读取输出
TestOutputTopic<String, String> output = driver.createOutputTopic(
"eventd-cleaned", new StringDeserializer(), new StringDeserializer());
assertEquals("ORDER", parseType(output.readValue())); // 清洗管道会把 type 转大写
Flink:本地执行与 MiniCluster
在 IDE 里直接运行 StreamExecutionEnvironment.getExecutionEnvironment() 就会用本地线程执行,不需要集群,也不需要手工启动 MiniCluster。
需要模拟多个 TaskManager/Slot、验证作业提交或 Checkpoint 行为时,用 JUnit 5 的 MiniClusterExtension,并通过它提供的客户端提交作业。只调用 cluster.start() 再执行 getExecutionEnvironment() 并不会把作业提交到那个集群——两者之间没有自动连接。完整写法见 13.2 Flink DataStream 测试
。
三种读法
路径 A:顺序通读(推荐)
- 第 1–3 章:流处理基础(Dataflow、窗口、Kafka Streams 入门)
- 第 4–8 章:Flink 核心(DataStream、Watermark、状态、Checkpoint、CEP)
- 第 9–12 章:eventd v3 实现(清洗→聚合→面板)
- 第 13–14 章:测试、性能、运维
路径 B:已有 Kafka Streams 经验
跳过第 2–3 章,从第 4 章(Flink DataStream)开始。重点看:
- 第 6 章(CEP):复杂事件模式匹配
- 第 8 章(测试与调优):MiniCluster、反压
- 第 11 章(端到端 EOS):Kafka → Flink → 下游
路径 C:只看代码
前言(环境)→ 第 9 章(eventd v3 架构)→ 附录 A(Flink 速查)→ 附录 B(Kafka Streams 速查)。
与卷一/卷二的衔接
| 卷 | 衔接点 |
|---|---|
| 卷一 | Flux/Mono 的背压概念 → Flink 的 backpressure 机制;Processor → Kafka Streams Processor API |
| 卷二 | eventd v2 的事件格式 → eventd v3 的输入;WebFlux SSE → 面板推送层;Micrometer 指标 → Flink MetricsReporter |
一个前置提醒
流处理代码的「正确」比「快」更难验证。批处理可以重跑,流处理的历史事件已经流逝。
本卷的示例按可测试方式组织;关键拓扑应配确定性测试:给定相同的输入事件序列,输出必须完全一致。这是流处理系统可追溯、可调试的基础。
环境就绪后,从流处理范式开始:1.1 Dataflow、窗口与时间语义 。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。