发版又出事故?我如何把回滚时间从40分钟压到90秒,附3种发布策略对比

🔑 关键词:版本发布,蓝绿部署,金丝雀发布,回滚策略,CI/CD

📖 摘要:一个踩了3年版本发布坑的业余开发者,对比滚动更新、蓝绿、金丝雀三种策略,分享具体参数和检查清单,把回滚时间从40分钟压到90秒。

去年11月10号晚上8点,我们发了一个订单服务的新版本,版本号v2.3.1,构建号build-20231110-1842。当时觉得就是改了个查询逻辑,加了个索引,应该没啥事。结果上线后5分钟,监控告警炸了:下单接口P99从200ms飙到8秒,数据库CPU直接100%。我赶紧回滚,结果发现回滚脚本没更新,还是上个版本的,跑了一半报错。最后手动改配置、重新构建镜像、回滚数据库迁移,折腾了40分钟,损失了大概2000个订单。说实话,那晚我抽了半包烟,心里就一个念头:回滚这么慢,发什么版?

图片

后来我把市面上常见的发布策略都试了一遍,说下我的对比。滚动更新是K8s默认的,参数maxSurge=25%,maxUnavailable=25%,意思是每次最多多起25%的Pod,同时最多停25%。它适合无状态服务,资源省,但回滚慢,因为要重新拉镜像、重新调度,我实测一个10个Pod的服务回滚要2-3分钟。蓝绿部署需要双倍资源,比如你有10个Pod,就要再准备10个。切换就是改Service的selector,瞬间完成,回滚也是切回来,我实测90秒搞定。但数据库迁移是噩梦,如果新版本改了表结构,旧版本代码不兼容,你切回去就报错。金丝雀发布是按比例放量,我一般设1%->5%->20%->50%->100%,每阶段观察5-10分钟,看错误率、P99、CPU。它最安全,但需要服务网格或者Ingress支持,而且全量时间很长,一个版本可能要磨1小时。我的独立观点是:别迷信单一策略,把金丝雀和蓝绿结合起来——先用金丝雀验证,全量后保留蓝绿环境,回滚直接切流量。

图片

再说几个我踩过的坑和解决方法。第一个是优雅停机。K8s默认发SIGTERM后立刻杀进程,正在处理的请求就断了。我们加了preStop钩子,执行sleep 15,让负载均衡先把Pod摘掉,再停服务。第二个是就绪探针,参数要调好:initialDelaySeconds: 10,periodSeconds: 5,failureThreshold: 3。太短了服务还没起来就重启,太长了发布慢。第三个是数据库迁移,必须向前兼容。比如加列可以,删列不行;改类型不行,加新列可以。我们用Flyway,每个版本一个迁移脚本,版本号跟应用版本对齐。第四个是配置管理,别把配置写死在镜像里。我们用ConfigMap,但有些配置改了要重启,后来改成用Apollo动态配置。第五个是回滚脚本,一定要和发布脚本一起写,一起测试。我们现在的回滚脚本会做三件事:切流量、回滚镜像、执行数据库回滚脚本(如果向前兼容就不需要)。

图片

最后给一个我现在的发布检查清单,你可以直接抄。1. 版本号用语义化版本,比如1.2.3,构建产物带git commit hash,方便追溯。2. 发布前跑一遍冒烟测试,至少覆盖核心接口。3. 灰度用户先选内部员工,再选1%种子用户,再10%,再全量。4. 监控看板必须有QPS、错误率、P99、CPU、内存,最好加个业务指标比如下单量。5. 发布窗口避开业务高峰,我们一般凌晨2点发,但别选周五。6. 每次发布后写复盘,哪怕没出事故也写,记录这次改了什么、观察了什么、下次注意什么。7. 保留人工确认环节,别全自动,尤其是数据库迁移。版本发布不是炫技,是保证业务连续。回滚速度才是发布能力的唯一指标,其他都是虚的。

图片

🏷️ 标签: