一、Flink 整体架构(四层模型)
scss
┌─────────────────────────────────────────────────────────────┐
│ Client Layer (客户端层) │
│ 你提交的代码 (Java/Scala/SQL) │
└──────────────────────┬──────────────────────────────────────┘
│ 提交作业
▼
┌─────────────────────────────────────────────────────────────┐
│ JobManager (JM) - 总厨/大脑 │
│ ┌─────────────────┐ ┌─────────────────┐ ┌──────────────┐ │
│ │ Dispatcher │ │ Checkpoint │ │ Scheduler │ │
│ │ (接收作业) │ │ Coordinator │ │ (调度器) │ │
│ │ │ │ (存档指挥官) │ │ │ │
│ └─────────────────┘ └─────────────────┘ └──────────────┘ │
│ 功能:决定谁干什么、什么时候存档、失败了怎么恢复 │
└──────────────────────┬──────────────────────────────────────┘
│ 分发任务
▼
┌─────────────────────────────────────────────────────────────┐
│ TaskManager (TM) - 工作站/干活的 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Slot 1 (灶台1) │ Slot 2 (灶台2) │ Slot 3 │ │
│ │ ┌───────────┐ │ ┌───────────┐ │ ┌─────────┐ │ │
│ │ │ Task 1 │ │ │ Task 2 │ │ │ Task 3 │ │ │
│ │ │ (Operator)│ │ │ (Operator)│ │ │(Operator)│ │ │
│ │ │ - 解析JSON│ │ │ - 关联校验│ │ │ - 写入DB│ │ │
│ │ └───────────┘ │ └───────────┘ │ └─────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
│ 功能:实际处理数据,维护本地状态 (State) │
└─────────────────────────────────────────────────────────────┘
关键组件解释:
| 组件 | 类比 | 职责 |
|---|---|---|
| JobManager | 餐厅总厨 | 协调全局,决定 Checkpoint 时机,分配任务给哪个工作站 |
| TaskManager | 工作站 | 实际干活(切菜、炒菜),每个 TM 有多个 Slot(灶台位置) |
| Slot | 灶台 | 资源单位,一个 Slot 跑一个 Task(一道工序) |
| Operator | 工序 | 具体逻辑(如 Map、Filter、Join),多个 Operator 可能链成一道 Task |
| State | 工作台上的半成品 | 处理过程中的中间结果(如当前计数、窗口缓存) |
二、数据流向(数据迁移场景)
以你的 MySQL → PostgreSQL 实时迁移 为例:
scss
MySQL Binlog → Flink Source → Transform → Sink → PostgreSQL
│ │ │ │
│ │ │ │
└──────────────┴────────────┴─────────┘
│
▼
┌───────────────────────┐
│ Checkpoint 机制 │
│ (每 10 秒全局拍照) │
└───────────────────────┘
详细流程:
- Source 算子 (数据入口):监听 MySQL Binlog,维护消费位点(Offset)
- Transform 算子 (你的 Java 逻辑):清洗、校验、转换,维护中间状态(如去重集合)
- Sink 算子 (数据出口):写入 PG,维护事务状态(预提交/已提交)
数据流向原则:
- 数据流式经过各个 Operator,不落地(或落本地 State)
- 每个 Operator 处理完向下游发送,同时更新自己的 State
三、Checkpoint 机制详解(实现原理)
Checkpoint 是 Flink 的分布式一致性快照 实现,核心解决 "挂了从哪恢复" 的问题。
1. 触发机制(谁说了算)
vbnet
JobManager (Checkpoint Coordinator)
│
│ 1. 定时触发(如每 10 秒)
▼
Source Operator ──→ 插入 Barrier(分界线)
│
│ 2. Barrier 随数据流向下传播
▼
Transform Operator ──→ 收到 Barrier,快照 State
│
▼
Sink Operator ──→ 收到 Barrier,预提交事务
│
│ 3. 所有算子报告成功
▼
JobManager ──→ 确认 Checkpoint 完成,通知正式提交
2. 核心概念:Barrier(分界线)
Barrier 是什么:
- 一种特殊标记,插入在数据流中,携带 Checkpoint ID
- 逻辑上把数据切成 "已快照" 和 "未快照" 两部分
图示:
css
数据流:A → B → C → [Barrier-1] → D → E → F → [Barrier-2]
↑
Checkpoint 1 快照点(包含 A,B,C)
和你的数据迁移对比:
- 你现在的做法:每处理 1000 条
commit一次(手动分界) - Flink 的做法:自动插入 Barrier,异步 分界,不阻塞处理
3. 对齐机制(Alignment)- 关键中的关键
当算子有多个输入流 (如 Join、Union)时,必须对齐:
arduino
Stream 1: 1 → 2 → [Barrier] → 3 → 4
Stream 2: X → Y → [Barrier] → Z → W
↑
对齐点
流程:
- Barrier 到达 Stream 1:暂停处理 Stream 1 的后续数据(3,4),缓存到缓冲区
- Barrier 到达 Stream 2:暂停处理 Stream 2 的后续数据(Z,W),缓存到缓冲区
- 两个 Barrier 都到了:快照当前 State(包含 1,2,X,Y 的处理结果)
- 恢复处理:释放缓存的 3,4,Z,W 继续处理
为什么需要对齐:
- 保证快照包含所有输入流的同一时刻状态
- 否则会出现"Stream 1 处理了 3,但 Stream 2 还没处理 Z"的不一致
Exactly-once vs At-least-once:
- Exactly-once(精准一次) :必须对齐,缓存数据可能产生背压(延迟)
- At-least-once(至少一次) :不对齐,哪个 Barrier 先到先快照,可能重复计算,但零延迟
4. State 快照实现(怎么存)
两层存储:
- 本地快照(同步) :算子将内存 State 写入本地 RocksDB(毫秒级)
- 远程持久化(异步) :后台线程将 RocksDB 文件上传到 HDFS/S3(秒级)
增量 Checkpoint:
- 不是每次全量备份,而是利用 RocksDB 的 SST 文件机制,只上传变更的文件
- 类比 Git:第一次全量 clone,之后只 push diff
5. 恢复流程(挂了怎么办)
arduino
作业失败
│
▼
JobManager 发现失败
│
▼
从最近成功的 Checkpoint 读取元数据
│
▼
重新分配 Task 到各个 TaskManager
│
▼
每个算子恢复 State(从 HDFS 下载到本地 RocksDB)
│
▼
Source 从记录的 Offset 重新开始消费
│
▼
作业恢复运行(精确到 Barrier 位置,不丢不重)
四、和你的 Java 程序对比(价值所在)
| 维度 | 你的 Java 迁移程序 | Flink Checkpoint 机制 |
|---|---|---|
| 容错粒度 | 手动控制(如每 1000 条 commit) | 自动、秒级、配置化 |
| 状态管理 | 自己维护 offset(可能存 Redis/MySQL) | 框架自动托管,分布式快照 |
| 多流对齐 | 难以实现(如同时读订单表和用户表,很难保证一致性) | Barrier 自动对齐 |
| 恢复速度 | 人工查日志,手动改 offset | 自动从 HDFS 恢复,秒级启动 |
| 一致性 | At-least-once(可能重复) | Exactly-once(精准一次) |
五、一句话总结(面试用)
Flink 的 Checkpoint 机制通过 Barrier 对齐实现分布式快照,将"流处理"转化为"有状态的流处理",在异步增量备份的前提下,实现了 Exactly-once 的容错语义,这是它区别于 Storm(无状态)和 Spark Streaming(微批)的架构核心竞争力。
对你现在的启示 : 你现在用 Java 写迁移脚本,相当于手动实现了一个简陋版的 Checkpoint (记录 offset + 事务提交)。Flink 把这个过程标准化、自动化、分布式化 了,让你可以专注于业务逻辑 (Transform),而把容错、恢复、一致性交给框架。