本节摘要:作业改了逻辑要发新版,跑了半年的状态怎么办?savepoint 是答案:一次全量、格式稳定、专为"搬家"设计的快照。本节讲清 checkpoint 与 savepoint 的分工、算子 UID 在状态映射中的关键作用、状态不兼容的典型场景与迁移手法,并给出一套可直接套用的升级流程。
每个维护过生产作业的人都知道那套流程:业务要改统计口径,代码改完了,测试环境验证通过,然后问题来了——直接重启部署,作业从零开始积累状态,去重要重新记、窗口要从头攒,几小时的业务数据被算乱。带着状态升级,靠的是 savepoint:人为触发的一次完整快照,格式跨版本稳定,专为"停下、搬家、接着跑"设计。本节是第 4 章从理论走向工程实务的一站。
两者技术上同源(都是分布式快照),定位却泾渭分明。checkpoint 是自动心跳:周期触发、追求轻快、可配置增量、格式允许随引擎版本演进优化,用途是故障恢复。savepoint 是人工手术:命令触发、强制全量、二进制格式长期稳定、允许"恢复时跳过未匹配的状态",用途是版本迁移、集群搬迁、扩缩容重平行化。
一句话记分工:checkpoint 防"天灾",savepoint 应"人祸"。天灾不可预期所以要快,人祸可以规划所以求稳。这也解释了为什么生产作业要用 savepoint 做定期归档:万一新版本上线发现严重问题要回滚,最近一次 savepoint 就是退路——回滚也是一次"搬家"。
savepoint 恢复时,引擎要回答一个匹配问题:旧作业的状态数据,该交给新作业里的哪个算子?匹配的钥匙是算子 UID。每个算子在快照里以 UID 登记,恢复时新作业按 UID 对号入座。由此推出生产开发的铁律:给每个关键算子显式指定 UID。
不显式指定的后果是 UID 由拓扑结构自动生成——你只是加了一个 map 算子,后续所有算子的自动 UID 全部变样,savepoint 恢复时通通对不上号,状态整卷作废。这类事故的特点是:测试环境一切正常(没有旧状态可恢复),一到生产升级日爆雷。所以 UID 要在第一次上线时就写进代码,而不是出事后补:
SingleOutputStreamOperator<Stat> stats = payments .keyBy(Payment::getShopId) .window(SlidingEventTimeWindows.of(Time.hours(1), Time.minutes(1))) .aggregate(new AmountAgg()) .uid("agg-window-shop-stat") // 稳定的身份号:跨版本状态映射的锚点 .name("shop-stat");
升级时最怕"恢复报错:状态类型不兼容"。常见三种情形。情形一:类型变了——把 ValueState 的值类型从整数改成字符串,旧数据无法解读。处置:换一个新的状态名(描述符改名),旧状态自然废弃,另写初始化逻辑重建;或者接受从 savepoint 里丢弃该状态重新积累。情形二:Pojo 结构加字段——通常兼容,新字段取默认值;删字段或改字段类型则视序列化器而定,升级前务必在测试环境用旧 savepoint 演练一次。情形三:算子并行度变了——键控状态按 key 哈希分布,并行度改变时状态会被重新洗牌分配,savepoint 恢复天然支持;这恰是 savepoint 相对 checkpoint 的一个独门用途(扩容不丢状态)。
流程里有三个容易忽略的检查点。其一,触发停止时用"停止并保存"而不是"粗暴取消",前者等快照写完才退出,返回的快照路径是唯一有效的恢复凭证。其二,新作业启动参数里显式带上快照路径与"允许未恢复状态"的取舍:默认遇到对不上的状态会拒绝启动(防止静默丢状态),确认作废才放开。其三,恢复后别急着宣布成功——观察第一个完整 checkpoint 周期是否正常、抽样核对几条指标与旧版衔接,连续才是升级完成的标志。
💡 关键直觉:savepoint 的成本高在"全量",所以它不替代心跳,只守护变更。变更日之外的稳定性,永远交给 checkpoint;把两者混用的团队,要么升级慢如蜗牛,要么心跳重得喘不过气。
状态不兼容的三情形之外,savepoint 还有一项 checkpoint 不具备的独门用途:带着状态改并行度。业务量翻倍后想给聚合算子扩容,直接改并行度重启会让键控状态按新并行度重新哈希分布——checkpoint 恢复虽也能做键的重分布,但日常心跳恢复并不触发重分配逻辑;而 savepoint 恢复原生支持"以新并行度读旧状态",键控状态会按键重新洗牌,算子状态则按列表切分或联合分配的策略处理。扩容的标准动作因此定型:先停并保存快照,再用新并行度从快照启动。整个过程业务无感,状态一个不丢。这也解释了为什么 6.1 节说 Kubernetes Operator 的升级参数默认配 savepoint 模式——扩缩容与版本升级共用同一条"带状态搬家"的通道。
心脏的肌肉、心跳、手术体系都讲完了。最后一站进急诊科:当 checkpoint 连续失败,如何按症状找到病根——那是把本章知识兑现成半夜里的处置能力。