从Savepoint恢复后数据重复了——Savepoint和Checkpoint有什么区别?
先说结论
| 维度 | Checkpoint | Savepoint |
|---|---|---|
| 触发方式 | 自动定期触发 | 手动触发(flink savepoint命令) |
| 用途 | 故障恢复(自动) | 作业升级、近移、调整并行度(手动) |
| 生命周期 | 作业结束后自动清理(默认) | 永久保存,手动删除 |
| 存储格式 | 特定于后端(RocksDB原生格式) | 标准化格式(跨版本兼容) |
| 增量支持 | 支持增量Checkpoint | 不支持(每次全量) |
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
Savepoint和Checkpoint是Flink里最容易混淆的两个概念。它们的技术原理几乎一样(都是状态快照),但用途和生命周期完全不同。而且很多人从Savepoint恢复后遇到“数据重复”的问题,今天把这些讲清楚。
典型使用场景
场景一:作业升级(最常见)
你修改了作业的逻辑需要重新部署。流程:
- 手动触发Savepoint:flink savepoint
hdfs:///savepoints/ - 停止旧作业:flink cancel
- 从Savepoint启动新作业:flink run -s hdfs:///savepoints/savepoint-xxx new-job.jar
场景二:调整并行度
发现作业反压需要加并行度。同样是Savepoint→停止→修改并行度→从Savepoint重启。
为什么从Savepoint恢复后会数据重复?
这是最常见的坑。原因是:
Savepoint只保存了Flink的状态,不保存Kafka的Offset提交状态。
具体来说:Savepoint里记录了Kafka的Offset(比如读到了offset=1000)。从Savepoint恢复后,Flink会从offset=1000重新消费。但如果Sink已经把offset=900-1000的数据写入了目标存储(而且Sink没有事务保证),那这部分数据就会被重复处理。
解决方案:
- Sink支持事务(如Kafka Exactly-Once Sink)→ 不会重复
- Sink支持幂等写入(如写入时带唯一键,重复写入也不会产生重复数据)→ 效果上不重复
- Sink不支持事务也不幂等(如纯追加写文件)→ 会重复,只能接受或下游去重
实战经验
我在元宇宙社交App时建立的Savepoint规范:
- 每次作业升级前必须先触发Savepoint
- Savepoint保留最近3个版本,方便回滚
- 所有Sink都必须支持幂等写入(带业务唯一键)
- 升级后观察30分钟确认无异常再删除旧Savepoint
总结
Checkpoint是自动故障恢复,Savepoint是手动作业升级。Savepoint恢复后数据重复的根因是Sink不支持事务/幂等。面试时能说清楚两者区别、Savepoint的使用流程、以及“为什么恢复后会重复”的原理和解决方案,就很有深度。
下一篇聊一个非常实用的话题:Flink读写Kafka的Connector配置和踩坑经验。
你们生产环境用Savepoint的频率是多少?评论区聊聊~
关注「Wood聊大数据」| 9年大数据老兵,聊技术、聊职场、聊成长