4. 迁移方案设计:迁移策略与回滚预案

方案设计这一步,说白了就是回答三个问题:怎么切?怎么验证?怎么回来?

我见过太多团队,花了两周搭流水线,结果上线时一拍脑袋选了个策略,出问题后又没有回滚手段,最后全员通宵回退代码。嗯,这种经历一次就够了。

这一章,我把三种主流迁移策略掰开揉碎讲清楚,再附上我自己的回滚预案模板。你照着搭,至少能保证:出事了,你能在 10 分钟内把用户拉回安全区。

4.1 三种迁移策略的核心逻辑

先看一张总览图,把三种策略的流量切换方式、风险等级和适用场景串起来。

迁移策略对比总览 蓝绿部署 流量瞬时切换 风险:高(全量切换) 回滚:秒级(切回蓝环境) 适用:核心链路、大版本 滚动升级 分批替换实例 风险:中(逐步暴露) 回滚:分钟级(分批回退) 适用:无状态服务、微服务 金丝雀发布 小比例流量验证 风险:低(灰度验证) 回滚:秒级(切回主版本) 适用:新功能、实验性版本 决策因素:业务容忍度 / 基础设施能力 / 团队响应速度 💡 我的建议:新项目从金丝雀开始,成熟服务用滚动升级, 核心链路必须保留蓝绿部署能力。三种策略可以组合使用。

4.2 蓝绿部署:最暴力也最可靠

蓝绿部署的思路很简单:同时维护两套完整环境。蓝环境跑当前生产版本,绿环境部署新版本。验证通过后,负载均衡器一键切换流量。

我在项目中遇到过最经典的场景:某金融核心系统迁移。业务要求停机时间不超过 30 秒,但数据库 schema 变更需要跑 20 分钟。怎么办?

我们用蓝绿部署 + 数据库双写解决了。提前在绿环境跑完 migration,数据同步追上后,直接切 DNS。整个过程用户无感知。

蓝绿部署的 Pipeline 示例

# 伪代码:蓝绿部署流水线核心步骤
stages:
  - deploy-green
  - smoke-test
  - switch-traffic
  - health-check
  - cleanup-blue

deploy-green:
  script:
    - kubectl apply -f k8s/green-deployment.yaml
    - kubectl rollout status deployment/green-app -n production

smoke-test:
  script:
    - curl -f https://green.internal.example.com/health
    - ./run-smoke-tests.sh --target green

switch-traffic:
  script:
    - kubectl patch service myapp -n production \
      --patch '{"spec":{"selector":{"version":"green"}}}'

health-check:
  script:
    - curl -f https://api.example.com/health
    - ./verify-business-logic.sh

cleanup-blue:
  script:
    - kubectl delete deployment blue-app -n production
    - kubectl delete configmap blue-config -n production
  when: always
⚠️ 注意:蓝绿部署的资源消耗是双倍的。如果你的集群资源紧张,可以考虑「逻辑蓝绿」—— 只保留一套数据层,应用层做蓝绿切换。但数据库回滚会复杂很多。

4.3 滚动升级:温水煮青蛙,但安全

滚动升级适合微服务架构。它不会一次性替换所有实例,而是逐个或逐批替换。Kubernetes 的 Deployment 默认就是滚动更新策略。

我个人习惯把滚动升级的批次大小控制在 20% - 30%。太小了耗时太长,太大了风险集中。举个例子:10 个 Pod 的服务,我分 3 批,每批 3-3-4 个。

滚动升级的关键参数

参数 推荐值 说明
maxSurge 25% 升级期间允许超出期望副本数的比例
maxUnavailable 25% 升级期间允许不可用副本的最大比例
minReadySeconds 30 新 Pod 就绪后等待多久才继续下一批
progressDeadlineSeconds 600 升级超时时间,超时自动回滚
💡 避坑指南:我曾经把 maxSurge 设成 50%,结果新版本有内存泄漏,瞬间拉起 5 个新 Pod 把集群内存打爆了。现在我的习惯是:maxSurge 不超过 25%,且配合 HPA 的 maxReplicas 上限一起使用。

4.4 金丝雀发布:用真实流量做验证

金丝雀发布的核心是:让一小部分真实用户先尝鲜。流量比例通常从 1% 或 5% 开始,观察一段时间后逐步放大。

你想想看,为什么叫金丝雀?以前矿工带金丝雀下井,鸟对毒气敏感,鸟死了人就撤。金丝雀发布也是这个道理 —— 让新版本先暴露在低风险流量下,出问题也只影响少数用户。

金丝雀发布的流量路由策略

# Istio VirtualService 示例:5% 流量到金丝雀版本
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: myapp-canary
spec:
  hosts:
  - myapp.example.com
  http:
  - match:
    - headers:
        x-canary:
          exact: "true"
    route:
    - destination:
        host: myapp
        subset: canary
      weight: 100
  - route:
    - destination:
        host: myapp
        subset: stable
      weight: 95
    - destination:
        host: myapp
        subset: canary
      weight: 5

金丝雀发布的典型节奏:

  1. 1% 流量 → 运行 10 分钟,检查错误率和延迟
  2. 5% 流量 → 运行 30 分钟,检查业务指标
  3. 20% 流量 → 运行 1 小时,观察是否有异常
  4. 50% 流量 → 运行 2 小时,确认稳定
  5. 100% 流量 → 全量发布,清理金丝雀环境

每个阶段如果指标异常,立即切回 0%。

4.5 回滚预案设计:别等出事了再想

回滚预案不是写在文档里吃灰的。它应该是可执行的、自动化的、经过演练的。

我曾经吃过一次大亏:某次数据库迁移,回滚脚本写好了但没测试。结果真出问题时,回滚脚本跑了一半报错,数据处于中间状态。最后 DBA 手动修了 6 个小时。

从那以后,我的回滚预案必须满足三个条件:

  • 可自动化:回滚操作必须能一键触发,不需要人工 SSH 上去敲命令
  • 可验证:回滚完成后有自动化校验,确认数据一致性和服务健康
  • 有时限:明确回滚的 RTO(恢复时间目标),超过时限自动升级

回滚预案模板

阶段 操作 负责人 预期耗时
检测异常 监控告警触发(错误率 > 1% 或 P99 延迟 > 500ms) 值班 SRE 1 分钟
确认回滚 在 CI/CD 平台点击「回滚」按钮 值班 SRE 30 秒
执行回滚 Pipeline 自动执行:切流量 / 恢复数据库 / 回退版本 自动化 2-5 分钟
健康检查 自动运行 smoke test 和业务校验 自动化 1 分钟
通知通报 发送回滚完成通知到企业 / Slack 自动化 10 秒
⚠️ 数据库回滚是最大的坑:应用层回滚很简单,但数据库 schema 变更(如删除列、修改字段类型)往往是不可逆的。我的建议是:数据库变更永远走「向前兼容」模式—— 先加新字段,再改代码,最后删旧字段。这样即使回滚,旧代码也能正常工作。

4.6 策略选择矩阵

最后,给你一个我实际项目中用的决策矩阵。遇到迁移场景时,对着这个表选策略就行。

场景 推荐策略 理由
核心交易系统 蓝绿部署 需要秒级回滚,资源消耗可接受
无状态 API 服务 滚动升级 资源利用率高,分批验证风险可控
新功能灰度上线 金丝雀发布 用真实流量验证,影响面最小
数据库迁移 蓝绿 + 双写 数据一致性要求高,需要完整环境验证
配置变更 金丝雀 + 滚动 先小范围验证配置正确性,再全量推送

说白了,没有银弹。每种策略都有它的适用边界。我的习惯是:在 Pipeline 里同时保留三种策略的模板,上线前根据变更类型和风险等级,选一个或组合使用。