2. Flink 核心概念与架构
这一章,我们来啃 Flink 最核心的骨架。说实话,很多运维同学把 Flink 当成一个黑盒,任务挂了重启,数据延迟了加资源。但如果你不理解它的数据流模型和运行时架构,遇到复杂故障时基本只能靠猜。我个人习惯,学任何系统先看它的数据模型——它决定了你能做什么、不能做什么。
2.1 Flink 数据流模型
Flink 的数据流模型,说白了就是「一切皆流」。它不像 Spark 那样把数据切成一批批的微批次,而是每来一条数据就处理一条。这个区别,在实时场景下是致命的。
2.1.1 数据流与转换
Flink 把数据抽象成 DataStream,你可以对它做各种转换操作。我画了一张图,帮你快速建立整体认知:
数据源可以是 Kafka、Socket 或者文件。Flink 把它们统一抽象成 DataStream,然后你可以在上面做各种转换。这里有个关键点:数据流分为有界和无界。有界流就是批处理,无界流才是真正的流处理。
2.1.2 窗口与时间语义
流处理里,窗口是个绕不开的概念。数据是源源不断的,但计算往往需要在一个「时间段」或「事件数量」内聚合。Flink 提供了三种窗口:
| 窗口类型 | 说明 | 适用场景 |
|---|---|---|
| Tumbling Window | 固定大小,不重叠 | 每分钟统计 PV |
| Sliding Window | 固定大小,可重叠 | 每 5 秒统计最近 1 分钟数据 |
| Session Window | 基于不活动间隔 | 用户行为会话分析 |
时间语义这块,我建议你重点理解 Event Time。Processing Time 虽然简单,但在生产环境里基本不靠谱。为什么?因为数据到达顺序是乱的,网络延迟、背压都会导致时间错乱。
2.2 运行时架构
理解了数据流模型,我们再来看 Flink 是怎么跑起来的。运行时架构就两个核心角色:JobManager 和 TaskManager。我习惯把它们比作「项目经理」和「一线工人」。
2.2.1 JobManager
JobManager 是集群的「大脑」。它负责接收作业、调度任务、协调 Checkpoint。在 Flink 1.9 之后,JobManager 支持 Standalone 和 Active-Passive 两种高可用模式。
JobManager 内部有三个关键组件:
- ResourceManager:管理资源,向 TaskManager 申请 Slot
- Dispatcher:接收作业提交,启动 JobMaster
- JobMaster:每个作业一个,负责调度和 Checkpoint
运维要点: JobManager 的 JVM 参数要格外注意。我见过太多人把 JobManager 堆内存设得和 TaskManager 一样大,结果资源全浪费了。JobManager 主要做调度和元数据管理,2-4GB 堆内存通常就够了,除非你同时跑几十个作业。
2.2.2 TaskManager
TaskManager 是真正干活的。每个 TaskManager 有多个 Slot,Slot 是资源调度的最小单位。一个 Slot 可以运行一个 SubTask。
这里有个容易混淆的点:Slot 隔离的是内存,不是 CPU。CPU 是共享的。所以如果你有两个 CPU 密集型的任务放在同一个 TaskManager 上,它们会抢 CPU。
| 配置项 | 建议值 | 说明 |
|---|---|---|
| taskmanager.numberOfTaskSlots | 4-8 | 根据 CPU 核数设定 |
| taskmanager.memory.process.size | 4-16GB | 总内存,包含堆外内存 |
| taskmanager.memory.managed.size | 总内存的 40% | 用于排序、哈希等操作 |
2.3 状态管理与容错机制
状态管理是 Flink 区别于其他流处理引擎的核心能力。没有状态,流处理就只能做简单的过滤和转换。有了状态,你才能做累加、去重、Join 这些复杂操作。
2.3.1 状态类型
Flink 提供了两种状态:Managed State 和 Raw State。生产环境几乎只用 Managed State,因为它自动管理存储和容错。
Managed State 又分三种:
- ValueState:单个值,比如计数器
- ListState:列表,比如缓存最近 100 条记录
- MapState:键值对,比如用户画像
状态后端决定了状态存在哪里。Flink 支持三种:
| 状态后端 | 存储位置 | 适用场景 |
|---|---|---|
| MemoryStateBackend | TaskManager 内存 | 开发测试,状态小 |
| FsStateBackend | TaskManager 内存 + 文件系统 | 生产环境,状态中等 |
| RocksDBStateBackend | RocksDB(本地磁盘) | 生产环境,状态大(GB 级) |
2.3.2 Checkpoint 与 Savepoint
容错机制的核心是 Checkpoint。Flink 通过分布式快照,定期保存所有算子的状态。一旦任务失败,就从最近的 Checkpoint 恢复。
Checkpoint 的关键配置:
- interval:间隔时间,默认 10 秒。太短影响性能,太长恢复慢
- timeout:超时时间,默认 10 分钟。超过就丢弃
- minPauseBetweenCheckpoints:最小间隔,防止频繁触发
Savepoint 和 Checkpoint 很像,但 Savepoint 是手动触发的,用于版本升级、作业迁移。我建议每次上线前都手动打一个 Savepoint。
运维口诀: Checkpoint 保命,Savepoint 保升级。Checkpoint 自动跑,Savepoint 手动打。两者都用 RocksDB 后端,别混用。
2.3.3 精确一次语义
Flink 号称支持「精确一次」语义。但说实话,这个「精确一次」是有条件的。它依赖于 Checkpoint 和 Kafka 等 Source/Sink 的幂等性。
实现原理:
- Source 记录当前消费的偏移量到状态中
- Checkpoint 时,将偏移量和算子状态一起快照
- 恢复时,从 Checkpoint 读取偏移量,重新消费
- Sink 端需要支持幂等写入或事务写入
最后,我画了一张运行时架构图,帮你把 JobManager、TaskManager、状态后端和 Checkpoint 串起来:
这一章的内容就到这里。数据流模型、运行时架构、状态管理和容错机制,是 Flink 运维的三大基石。你把这些搞透了,后面遇到性能调优、故障排查才不会慌。