Flink和CheckPoint简单了解

0 阅读5分钟

一、Flink 整体架构(四层模型)

┌─────────────────────────────────────────────────────────────┐
│  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 实时迁移 为例:

MySQL Binlog → Flink Source → Transform → Sink → PostgreSQL
     │              │            │         │
     │              │            │         │
     └──────────────┴────────────┴─────────┘
                    │
                    ▼
        ┌───────────────────────┐
        │    Checkpoint 机制     │
        │  (每 10 秒全局拍照)    │
        └───────────────────────┘

详细流程

  1. Source 算子(数据入口):监听 MySQL Binlog,维护消费位点(Offset)
  2. Transform 算子(你的 Java 逻辑):清洗、校验、转换,维护中间状态(如去重集合)
  3. Sink 算子(数据出口):写入 PG,维护事务状态(预提交/已提交)

数据流向原则

  • 数据流式经过各个 Operator,不落地(或落本地 State)
  • 每个 Operator 处理完向下游发送,同时更新自己的 State

三、Checkpoint 机制详解(实现原理)

Checkpoint 是 Flink 的分布式一致性快照实现,核心解决 "挂了从哪恢复" 的问题。

1. 触发机制(谁说了算)

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
  • 逻辑上把数据切成 "已快照""未快照" 两部分

图示

数据流:AB → C → [Barrier-1] → D → E → F → [Barrier-2]
                    ↑
            Checkpoint 1 快照点(包含 A,B,C)

和你的数据迁移对比

  • 你现在的做法:每处理 1000 条 commit 一次(手动分界)
  • Flink 的做法:自动插入 Barrier,异步分界,不阻塞处理

3. 对齐机制(Alignment)- 关键中的关键

当算子有多个输入流(如 Join、Union)时,必须对齐

Stream 1:  12 → [Barrier] → 34
Stream 2:  X → Y → [Barrier] → Z → W
                  ↑
              对齐点

流程

  1. Barrier 到达 Stream 1:暂停处理 Stream 1 的后续数据(3,4),缓存到缓冲区
  2. Barrier 到达 Stream 2:暂停处理 Stream 2 的后续数据(Z,W),缓存到缓冲区
  3. 两个 Barrier 都到了:快照当前 State(包含 1,2,X,Y 的处理结果)
  4. 恢复处理:释放缓存的 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. 恢复流程(挂了怎么办)

作业失败
   │
   ▼
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),而把容错、恢复、一致性交给框架。