第2章:Flink基础回顾:Flink架构、核心概念与开发环境搭建
各位同学,咱们直接进入正题。这一章我打算带大家快速过一遍Flink的核心基础。别觉得枯燥,这些概念在后面的CEP实战中会反复出现。我自己带风控项目时,发现很多问题其实都出在基础概念没吃透上。
2.1 Flink架构:它到底是怎么跑的?
先看整体架构。Flink是一个分布式计算引擎,说白了就是一群机器协同干活。我习惯把它的架构分成三层:
- Client层:你提交作业的地方。它负责把代码打包、配置参数,然后扔给集群。
- JobManager:大脑。负责调度、协调、故障恢复。一个集群只有一个活跃的JobManager。
- TaskManager:苦力。真正干活的计算节点,每个TaskManager有多个Slot(插槽),Slot就是计算资源的最小单位。
嗯,这里要注意:Slot的数量决定了你的并行度上限。我在项目中遇到过,有人把并行度设得比Slot数还大,结果任务一直pending。你想想看,资源不够怎么跑?
核心要点:JobManager负责管理,TaskManager负责计算。两者通过Akka通信。
下面这张图是我自己画的架构流程,帮你理清数据是怎么流转的:
2.2 核心概念:DataStream、时间语义、Watermark
2.2.1 DataStream:一切皆流
在Flink里,所有数据都被抽象成DataStream。你可以把它想象成一条永不停歇的数据河流。每条数据就是一个事件,比如用户点击、交易记录、设备上报。
我个人习惯把DataStream分成两类:
- 有界流:数据有终点,比如读取一个文件。处理完就结束。
- 无界流:数据源源不断,比如Kafka消息。风控场景99%都是无界流。
小提示:在风控中,我们几乎只用无界流。因为攻击行为随时可能发生,你不能等数据全了再分析。
2.2.2 时间语义:你到底以哪个时间为准?
这是Flink里最容易搞混的概念。我刚开始学的时候也绕了很久。Flink支持三种时间:
| 时间类型 | 含义 | 风控场景举例 |
|---|---|---|
| Event Time | 事件实际发生的时间 | 用户点击按钮的瞬间(最常用) |
| Ingestion Time | 数据进入Flink的时间 | 数据到达Source算子的时刻 |
| Processing Time | 算子处理数据的当前时间 | 机器本地时钟(延迟最低) |
为什么强调这个?因为风控场景里,事件乱序是家常便饭。比如用户先点了支付,但网络延迟导致支付事件比点击事件还晚到。如果你用Processing Time,那分析结果就全错了。
避坑指南:我曾经在风控项目里默认用了Processing Time,结果发现同一个用户的支付事件比点击事件先到,导致风控规则误判。后来全部改成Event Time才解决。记住:风控场景,永远优先用Event Time。
2.2.3 Watermark:解决乱序的利器
Watermark说白了就是一个「时间进度条」。它告诉Flink:到这个时间点为止,该来的数据都来了,没来的就当丢了,可以触发计算了。
举个例子:假设你设置Watermark延迟为5秒。当前Event Time是12:00:10,那么Watermark就是12:00:05。Flink会认为12:00:05之前的数据已经到齐,可以开始计算窗口了。
Watermark的生成方式有两种:
- 周期性生成:每隔N毫秒生成一次。适合大部分场景。
- 逐条生成:每条数据都生成。适合对延迟极度敏感的场景。
// 我常用的周期性Watermark生成方式
DataStream<Event> stream = env
.addSource(kafkaConsumer)
.assignTimestampsAndWatermarks(
WatermarkStrategy.<Event>forBoundedOutOfOrderness(Duration.ofSeconds(5))
.withTimestampAssigner((event, timestamp) -> event.getEventTime())
);
核心要点:Watermark不是真实数据,它只是一个逻辑标记。它的作用是告诉Flink「可以安心计算了」。
2.3 Flink开发环境搭建:5分钟跑起来
这部分我尽量简洁。你不需要搞太复杂,一个本地环境足够我们学完整个课程。
2.3.1 环境要求
- JDK 8 或 11(我推荐JDK 11,性能更好)
- Maven 3.6+(用于构建项目)
- IDE:IntelliJ IDEA(我个人习惯用这个)
2.3.2 创建Flink项目
我建议直接用Maven Archetype生成,省事:
mvn archetype:generate \
-DarchetypeGroupId=org.apache.flink \
-DarchetypeArtifactId=flink-quickstart-java \
-DarchetypeVersion=1.17.1 \
-DgroupId=com.risk.cep \
-DartifactId=flink-cep-course \
-Dversion=1.0-SNAPSHOT
2.3.3 核心依赖
在pom.xml里加上CEP的依赖,后面章节会用到:
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-cep</artifactId>
<version>1.17.1</version>
</dependency>
2.3.4 验证环境
写一个最简单的WordCount跑一下,能正常输出就说明环境没问题。嗯,这一步别跳过,我见过有人依赖冲突搞了半天。
public class WordCount {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
DataStream<String> text = env.socketTextStream("localhost", 9999);
text.flatMap((String line, Collector<Tuple2<String, Integer>> out) -> {
for (String word : line.split(" ")) {
out.collect(new Tuple2<>(word, 1));
}
})
.keyBy(value -> value.f0)
.sum(1)
.print();
env.execute("WordCount");
}
}
小提示:本地调试时,我习惯用socketTextStream配合nc命令手动输入数据,比连Kafka方便多了。
好了,基础回顾就到这里。这些概念在后面的CEP实战中会反复用到,尤其是Watermark和Event Time,它们是风控规则准确性的基石。下一章我们直接进入CEP核心模式,到时候你会感谢今天打下的基础。
公众号:蓝海资料掘金营,微信deep3321