灰度发布、金丝雀发布与快速回滚
生产发布不是把新版本复制到全部服务器,而是一个持续验证风险的过程。灰度发布通过控制影响范围、观察关键指标并设置自动停止条件,让错误尽可能早暴露在少量流量中。快速回滚则要求旧版本、配置、数据结构和流量入口都具备可恢复路径。
本文适用于 Web 服务、API、微服务和 Kubernetes 工作负载。它不能替代单元测试、集成测试与安全评审,而是上线前最后一道生产保护。
一、发布方式怎么选
| 方式 | 核心思路 | 优点 | 主要风险 |
|---|---|---|---|
| 滚动发布 | 分批替换旧实例 | 资源需求较低 | 新旧版本同时存在,回退可能较慢 |
| 蓝绿发布 | 两套完整环境切换流量 | 切换和回退快 | 资源成本高,数据库仍需兼容 |
| 金丝雀发布 | 少量实例或流量先使用新版本 | 控制影响范围,可量化比较 | 指标和流量分配设计复杂 |
| Feature Flag | 发布代码后再逐步启用功能 | 功能上线与二进制发布解耦 | 标志长期不清理会形成复杂分支 |
| 影子流量 | 复制真实请求到新系统,不返回结果 | 接近真实流量且不影响响应 | 有状态写入必须隔离,成本较高 |
同一系统可以组合使用。例如先用蓝绿环境准备新版本,再把 5% 流量导向绿色环境形成金丝雀。
二、建立发布准入条件
发布前应满足:
- 构建产物可追溯到提交、流水线和依赖清单;
- 自动化测试和安全检查通过;
- 配置差异已审阅,敏感信息不进入代码仓库;
- 数据库变更具备前向和后向兼容性;
- 监控可以区分版本、实例、区域和流量组;
- 回滚产物仍然可用,回滚命令经过测试;
- 发布负责人、观察人和停止权限明确;
- 已知风险、用户影响和客服口径已记录。
如果无法区分新旧版本的指标,就无法判断金丝雀是否更差,只能称为“分批发布”。
三、选择金丝雀人群
金丝雀流量应具有代表性,同时限制爆炸半径。常用维度包括:
- 内部员工或测试账号;
- 单个租户、地区、可用区或机房;
- 特定设备、客户端版本或请求头;
- 随机百分比流量;
- 无状态只读接口优先;
- 风险较低但请求模式完整的业务路径。
不要只选“最简单、最稳定”的请求,否则无法覆盖新版本的真实风险。涉及支付、删除、消息发送的写路径,应先验证幂等和数据隔离。
四、设计发布阶梯
典型阶梯不是固定答案,可以从以下结构开始:
阶段 0:0% 用户流量,完成启动、健康检查和合成探测
阶段 1:1% 流量,观察 10~15 分钟
阶段 2:5% 流量,观察一个短业务周期
阶段 3:20% 流量,覆盖主要请求类型
阶段 4:50% 流量,确认依赖与容量变化
阶段 5:100% 流量,继续保留回退窗口
低流量系统可能需要更长时间才能获得有效样本;高频系统可以缩短时间,但不能短到队列、缓存和定时任务尚未表现。批处理、结算和日终任务应按业务周期观察。
五、定义自动判断指标
至少比较新版本和对照组,而不是只检查固定阈值:
| 维度 | 指标示例 | 停止条件示例 |
|---|---|---|
| 正确性 | 业务失败率、结果一致性 | 相对对照组上升 20% |
| 可用性 | HTTP 5xx、超时率 | 连续 5 分钟超过 SLO |
| 性能 | P95、P99、队列等待 | P99 高于对照组 30% |
| 资源 | CPU、内存、GC、连接 | 资源斜率持续异常 |
| 依赖 | 数据库、缓存、第三方错误 | 下游错误或限额显著增加 |
| 业务 | 登录成功率、支付成功率 | 核心转化出现统计显著下降 |
固定阈值用于防止绝对故障,对照组比较用于发现新版本回归。样本太少时不要得出“新版本正常”的结论。
六、把 SLO 和错误预算接入发布
发布判断应优先使用用户体验指标。可以用短窗口和长窗口燃尽率组合:短窗口快速发现严重回归,长窗口避免瞬时噪声。若服务错误预算已经接近耗尽,应降低发布速度、缩小批次或暂停非必要变更。
发布流水线可以实现以下门禁:
若核心 SLI 达标,且新版本相对对照组无显著恶化:继续
若数据不足:延长观察,不自动判定成功
若触发硬性安全阈值:立即停止并回退
若只触发软阈值:暂停,要求人工评估
七、数据库变更必须可兼容
应用回滚失败最常见的原因之一,是数据库已经变成旧版本无法理解的结构。建议使用 Expand—Migrate—Contract:
- Expand:先添加新字段或新表,不删除旧结构;
- Deploy:新旧应用同时兼容两种结构;
- Migrate:后台迁移历史数据并校验;
- Switch:逐步切换读写路径;
- Contract:确认回滚窗口结束后再删除旧结构。
禁止在同一发布步骤中直接重命名字段、删除列并切换全部应用。大表 DDL 还要评估锁、复制延迟、日志量和磁盘空间。
八、配置和功能开关
Feature Flag 应有:
- 所有者、用途和影响范围;
- 默认值及失效行为;
- 启用条件和紧急关闭方式;
- 创建日期、计划清理日期;
- 访问审计和权限控制;
- 服务端兜底,不能只依赖前端隐藏。
开关不是永久配置中心。发布完成后应删除过期开关和分支逻辑,否则测试组合呈指数增长。
九、快速回滚的真实要求
回滚不只是执行 kubectl rollout undo。完整回滚需要检查:
- 旧镜像或安装包仍存在且签名可验证;
- 旧配置可以恢复,且密钥版本仍有效;
- 数据库结构允许旧版本运行;
- 消息格式、缓存键和 API 合约向后兼容;
- 流量入口、DNS、CDN 和负载均衡能恢复;
- 后台任务不会由两个版本重复执行;
- 回滚后执行业务探测,而不是只看 Pod Ready。
定义回滚时间目标,例如从决定回滚到用户核心路径恢复不超过 10 分钟,并在非生产环境演练。
十、Kubernetes发布示例思路
一个受控流程可以是:
steps:
- setWeight: 5
- pause: {duration: 10m}
- analysis: {templates: [service-slo-check]}
- setWeight: 20
- pause: {duration: 20m}
- analysis: {templates: [service-slo-check, dependency-check]}
- setWeight: 50
- pause: {duration: 30m}
此片段只表达策略。实际字段以所使用的渐进式交付控制器版本为准。分析模板应查询与该版本、该服务相关的指标,并处理监控无数据、查询失败和样本不足。
十一、一次完整发布案例
某查询服务准备发布缓存策略变更:
- 预发布环境使用生产脱敏流量回放;
- 新版本启动后只接受合成探测;
- 导入 2% 真实读流量,比较命中率、P99 与数据库 QPS;
- 发现缓存命中率提升,但数据库连接创建速率异常;
- 自动门禁暂停发布,确认新客户端未复用连接;
- 修复后重新构建制品,从 2% 重新开始;
- 20%、50% 阶段均通过,最终全量;
- 保留旧版本和开关 24 小时,再结束回退窗口。
关键点是发现问题后重新生成可追溯制品,而不是直接进入容器临时修改。
十二、发布期间的职责
| 角色 | 主要职责 |
|---|---|
| 发布负责人 | 推进阶段、记录决定、发起暂停或回退 |
| 服务负责人 | 判断业务正确性和已知风险 |
| 观察人员 | 监控 SLI、依赖和资源变化 |
| 数据库负责人 | 审核结构变更、迁移和复制状态 |
| 值班人员 | 接收用户侧异常,避免信息断层 |
高风险发布不应由一个人同时操作、观察和决定。夜间发布也不天然更安全;低流量可能导致样本不足,且人员响应能力更弱。
十三、发布记录模板
变更编号:CHG-2026-001
制品版本及摘要:app:v2.4.1 / sha256:...
数据库变更:新增可空字段,无破坏性删除
灰度维度:随机用户 + 单可用区
阶段:2% → 10% → 25% → 50% → 100%
核心指标:成功率、P99、数据库 QPS、队列长度
硬停止条件:错误率 > 1% 或关键业务失败
回滚操作:恢复流量权重并部署上一签名制品
回滚验证:登录、查询、写入、异步任务
负责人和观察人:...
十四、常见失败方式
- 只按实例数量灰度,但负载均衡没有真正导入流量;
- 观察 CPU 正常就继续,不检查业务错误和长尾延迟;
- 新旧版本写入不兼容消息,回滚后无法消费;
- 数据库迁移与应用全量发布同时进行;
- 监控查询无数据时被当作“通过”;
- 发生异常后继续扩大流量,等待更多证据;
- 发布完成立即删除旧制品和功能开关;
- 回滚只恢复应用,不验证缓存、队列和定时任务。
十五、上线检查清单
- [ ] 发布制品可追溯且不可在服务器上临时修改;
- [ ] 金丝雀与对照组指标能够分开查询;
- [ ] 定义了阶段、观察时长、硬停止和软暂停条件;
- [ ] 数据库、消息和 API 具备双向兼容窗口;
- [ ] 监控无数据不会被误判为成功;
- [ ] 回滚覆盖应用、配置、流量和数据兼容性;
- [ ] 发布完成后继续观察一个业务周期;
- [ ] Feature Flag 有所有者和清理日期;
- [ ] 发布记录可用于事故复盘和效果改进。