1. 状态后端概述:什么是状态后端、核心作用与状态存储的区别

好,咱们正式开始状态后端切换的全流程演练。第一节课,先把基础打牢。

很多同学刚接触 Flink 时,看到「状态后端」这个词就有点懵。我当年也一样,心想:不就是存个状态吗,怎么还整出个「后端」来?

其实你把它拆开看就清楚了——状态是 Flink 作业要记住的数据,后端是它存数据的地方。合起来,状态后端就是 Flink 用来管理、存储和恢复状态的底层组件。

1.1 什么是状态后端

状态后端,说白了就是 Flink 作业的「记忆仓库」。你的算子要记住中间结果、累加值、窗口数据,这些都得靠它。

Flink 官方文档里给的定义是:State Backend determines how state is stored and checkpointed. 翻译过来就是——它决定了状态怎么存、怎么做快照。

我个人习惯把状态后端比作数据库的存储引擎。MySQL 有 InnoDB、MyISAM,Flink 也有 HashMapStateBackend、EmbeddedRocksDBStateBackend。选哪个,直接影响你的作业能跑多快、能扛多大状态。

核心要点:状态后端是 Flink 运行时的一部分,它负责在算子运行时读写状态,并在 checkpoint 时把状态持久化到可靠存储。

1.2 状态后端的核心作用

状态后端到底干了哪些活?我总结了三个核心职责:

  1. 状态读写——算子运行时,get/put 状态数据全靠它。读写性能直接决定算子延迟。
  2. 状态管理——包括状态的分配、序列化、内存控制。比如 RocksDB 会把状态写到磁盘,HashMap 则全在堆内存里。
  3. Checkpoint 与恢复——做快照时,状态后端负责把当前状态快照出来,写到远程存储(HDFS、S3)。故障恢复时,再从远程拉回来重建。

嗯,这里要注意:第三个作用才是状态后端最关键的。没有 checkpoint,状态后端就是个内存缓存,一挂全丢。

我在项目中遇到过一个问题:一个作业跑了两周,突然 TaskManager 挂了。重启后状态恢复花了 40 分钟。后来一查,是状态后端配置不当,RocksDB 的增量 checkpoint 没开。那次之后,我对状态后端的配置就格外上心了。

1.3 状态后端 vs 状态存储

这两个概念经常被混用,但它们的层次完全不同。我画了张图帮你理清关系:

状态后端 vs 状态存储:层次关系 Flink 运行时(JobManager / TaskManager) 状态后端(State Backend) 状态存储(State Storage) Checkpoint 存储 堆内存(Heap) RocksDB(磁盘) 状态后端 = 状态存储 + Checkpoint 存储 + 管理逻辑 状态存储只负责运行时读写,Checkpoint 存储负责持久化快照

从图上你能看到:状态后端是一个更上层的概念,它包含了状态存储和 checkpoint 存储,还负责管理逻辑。而状态存储只是状态后端的一部分,专门管运行时怎么读写数据。

举个例子你就明白了:

  • 状态存储:HashMapStateBackend 把状态存在 JVM 堆里,RocksDBStateBackend 把状态存在本地 RocksDB 实例里。这是「怎么存」的问题。
  • 状态后端:除了决定怎么存,还决定 checkpoint 怎么做——是全量快照还是增量快照?异步还是同步?这是「怎么管」的问题。
我的经验:面试时经常有人把这两个概念搞混。记住一句话——状态后端是「管理者」,状态存储是「执行者」。管理者决定策略,执行者负责干活。

1.4 三种状态后端对比

Flink 1.13 之后,状态后端做了重构。现在主流就三种:

状态后端 存储位置 适用场景 状态大小 读写性能
HashMapStateBackend JVM 堆内存 小状态、低延迟 建议 < 10GB 极高(纯内存)
EmbeddedRocksDBStateBackend 本地磁盘(RocksDB) 大状态、高吞吐 TB 级别 中等(序列化开销)
(已废弃)MemoryStateBackend JVM 堆 + JobManager 仅测试/调试 建议 < 5MB 极高但不可靠

注意看第三行——MemoryStateBackend 在 1.13 之后已经被标记为废弃。我曾经见过有团队在生产环境用这个,结果状态一涨,JobManager 直接 OOM。嗯,这是个坑,后面章节我会专门讲怎么避。

1.5 状态后端切换为什么重要

你可能会问:默认用 RocksDB 不就行了?为什么还要切换?

原因很简单——没有银弹。

  • HashMapStateBackend 快,但吃内存。状态一上 10GB,GC 能把你的延迟打飞。
  • RocksDBStateBackend 能扛大状态,但每次读写都要序列化/反序列化,延迟比堆内存高一个数量级。

我做过一个实时风控项目,刚开始用 HashMap,状态 3GB 时 GC 停顿已经到 5 秒了。切到 RocksDB 后,延迟虽然高了 30%,但 GC 问题彻底解决。这就是切换的价值——根据业务场景选最合适的。

注意:状态后端切换不是改个配置就完事的。它涉及 checkpoint 兼容性、状态迁移、作业重启策略。如果操作不当,可能导致状态丢失或恢复失败。后面几章我会手把手带你走完整个流程。

1.6 本章小结

来,我们快速过一遍今天的关键点:

  • 状态后端是 Flink 管理状态的底层组件,负责读写、管理和 checkpoint。
  • 核心作用有三:运行时读写、状态管理、checkpoint 与恢复。
  • 状态后端 ≠ 状态存储。状态存储是后端的子集,只管「怎么存」,后端还管「怎么管」。
  • 主流选择就两个:HashMapStateBackend(小状态、低延迟)和 EmbeddedRocksDBStateBackend(大状态、高吞吐)。