我为什么把“代码回滚”练成了肌肉记忆
我为什么把“代码回滚”练成了肌肉记忆
以前我觉得回滚是失败的标志。代码上线了还要回滚,说明我写的代码有问题,说明我测试不充分,说明我丢人。所以每次发布前我都反复自测,心里默念“这次一定没问题”,把回滚方案当摆设,从来没认真准备过。
直到那次上线后 10 分钟,生产环境开始报 OutOfMemoryError,服务一台接一台地挂。我手忙脚乱地翻回滚文档,发现步骤写的是“回滚到上一个版本”——但上一个版本的镜像 tag 是什么?没人记得。我赶紧去翻 CI 历史,找到 tag,执行回滚命令,结果报错:镜像仓库里那个 tag 被覆盖了。最后还是运维同学从节点上找到了缓存的旧镜像,手动拉起来才恢复。整个过程花了 47 分钟,而如果有现成的回滚脚本,本来 30 秒就能搞定。
那次事故之后,我把回滚从“最后的退路”变成了“第一优先级”。现在每次发布前,我做的第一件事不是检查新功能,而是确认:如果出问题,我能不能在 1 分钟内把系统恢复到上一个正常状态?
一、回滚不是认输,是专业
这个心态转变花了我很长时间。以前觉得回滚=打脸,现在觉得回滚=负责任。用户不关心你是因为什么 Bug 导致的故障,他们只关心服务什么时候恢复。你能 1 分钟回滚,还是 47 分钟抢修,这是专业和业余的区别。
我现在的准则是:任何发布,如果不能在 5 分钟内回滚,就不该发布。 5 分钟不是随便定的——这是用户投诉升级到上级的时间窗口,是监控系统从告警变成大面积故障的临界点。
二、回滚的三种姿势,各有利弊
1. 版本回退(最干净)
K8s 的 rollout undo 是最理想的回滚方式:
kubectl rollout undo deployment/order-service -n production
前提是:你保留了上一个版本的 ReplicaSet,镜像还在仓库里,配置没变。我们规定 CI 流水线必须保留最近 5 个版本的镜像和部署配置,不能覆盖 tag。
2. 配置开关(最优雅)
对于功能类发布,我用 Feature Flag 做回滚:
@GetMapping("/newFeature")
public Result newFeature() {
if (!featureFlagService.isEnabled("new_search", userId)) {
return oldSearch();
}
return newSearch();
}
出问题了?把开关关掉,新功能秒级下线,旧逻辑无缝接管。用户甚至感知不到。这种方式不需要回滚代码,只需要改一个配置,风险最低。
3. 数据库回滚(最危险)
代码能回滚,数据不能。如果新版本改了表结构、迁移了数据,回滚代码后老版本可能不兼容新数据。我的做法是:
- 所有数据库变更提前执行,且保证向前兼容。比如加字段用
ALTER TABLE ADD COLUMN,老代码不读这个字段,完全兼容。 - 不删字段、不删表,等确认新版本稳定后再清理。
- 数据迁移脚本必须可逆,有
up和down两个方向。
有一次我们上线前提前加了新字段,新代码写入,老代码忽略。发布后发现新代码有问题,直接回滚到老版本,老版本不读新字段,一切正常。这就是向前兼容的价值。
三、回滚演练:别等出事了才第一次跑
以前回滚是“出事了才做”,现在我们是定期演练。每月挑一个非高峰时段,随机选一个服务做回滚演练:把生产环境回滚到上一个版本,再滚回来。目的不是测试回滚能不能成功,而是:
- 验证回滚文档是否过时
- 验证镜像 tag 是否还在
- 验证团队成员是否记得操作步骤
- 验证回滚后监控是否能正常恢复
第一次演练时,我们发现回滚文档里写的命令在新版 K8s 里已经 deprecated 了,赶紧更新。如果这是真出事时才发现,又要多花 10 分钟查文档。
四、回滚的“三不”原则
- 不在高峰期做有风险的发布。大版本、数据库变更、架构调整,必须在流量低的时候发。
- 不跳过回滚检查。发布前必须确认:上一个版本的镜像在不在?配置文件有没有备份?回滚命令跑过没有?
- 不犹豫回滚时机。监控告警触发后 5 分钟内不能确认原因,直接回滚。别抱着“再看看”的侥幸心理——你多看的每一分钟,都是用户在承受损失。
五、一个意外收获:回滚倒逼出更好的发布策略
因为把回滚当成了第一优先级,我自然开始思考怎么让发布更安全:
- 金丝雀发布:先发一台,观察 5 分钟,没问题再全量
- 蓝绿部署:新旧版本同时跑,流量一键切换
- 滚动更新:分批替换,一台没问题再换下一台
这些策略不是为了炫技,是为了让回滚更简单——如果只发了一台就出问题,影响面极小,回滚也快。
一个心态的转变
以前我觉得回滚是“最坏的结果”,现在觉得是“最好的保险”。你买了车险不代表你想出车祸,但出了车祸你知道自己能兜底。回滚方案就是系统的车险——希望永远用不上,但必须有,而且得随时能用。
如果你现在的团队发布前还不准备回滚方案,今晚就花 10 分钟写一份:上一个版本的镜像 tag 是什么?回滚命令是什么?回滚后怎么验证?把答案写下来,贴到发布流程里。不用等“大版本”才准备——任何一次发布,都可能成为你需要回滚的那次。毕竟,Plan B 存在的意义,不是因为你不够自信,而是因为你足够负责。
- 点赞
- 收藏
- 关注作者
评论(0)