跳到主要内容

如何设计一个灰度发布系统?如何控制流量逐步切换到新版本?

灰度发布(Canary / Gray Release)是在 少量真实流量 上验证新版本,再 按阶段放大权重,出问题可快速回滚。面试要讲清:发布模型、流量调度、观测门禁、回滚与数据兼容。网关层权重路由见 API 网关设计与实现;熔断降级见 限流熔断与降级。

先澄清:灰度 vs 其它发布​

模式做法切换方式
滚动发布逐批替换 Pod/实例无精细流量比;旧版自然减少
蓝绿两套全量环境,一切开关0→100% 切换,回滚快但资源双倍
金丝雀/灰度新旧 同时在线,按规则分流量1%→5%→…→100% 渐进
功能开关代码在 trunk,开关控制逻辑与部署解耦,常配合使用

面试默认答 金丝雀灰度:新旧版本并存,可控比例 逐步切流。

系统目标​

目标说明
降风险新版本先接小流量,异常影响面小
可观测按版本对比错误率、延迟、业务指标
可回滚秒级把权重调回 0% 或切蓝绿
可自动化指标达标自动升档,不达标自动回滚

总体架构​

┌─────────────────┐
发布平台 / CI ───►│ 灰度控制面 │ 定义阶段、权重、门禁规则
│ (Admin/API) │
└────────┬────────┘
│ 推送配置
┌────────▼────────┐
用户请求 ────────►│ 流量调度层 │ 网关 / LB / Service Mesh
│ v1 ◄──90%──► v2 │
└────────┬────────┘
│
┌──────────────┼──────────────┐
▼ ▼ ▼
v1 实例 v2 实例 监控/日志
│ │ │
└──────────────┴──────────────┘
│
指标对比 → 自动升档 / 回滚
组件职责
控制面发布单、阶段、权重、白名单、审批
数据面网关 / Istio / Nginx 执行分流
注册中心实例带 version 标签,供 subset 路由
观测Prometheus + 按 version 维度 metrics
门禁错误率、P99 延迟、业务 KPI

流量如何逐步切换​

1. 按权重(最常用)​

# 逻辑配置
release_id: order-svc-20250818
stages:
- weight_v2: 1 # 1% → 观察 30min
- weight_v2: 5
- weight_v2: 20
- weight_v2: 50
- weight_v2: 100
rollback_on:
error_rate_v2 > error_rate_v1 * 1.5
p99_v2 > p99_v1 * 1.3

数据面实现:

方式说明
随机权重random(0,99) < weight → v2
LB 加权Nginx weight=1 vs weight=99
Mesh VirtualServiceIstio subset: v2 weight: 10

2. 按用户稳定分组(推荐配合权重)​

bucket = hash(user_id) % 100
if bucket < weight_v2 → v2
else → v1
优点说明
粘性同一用户多次请求打同一版本,体验一致
可调试内部账号固定进 v2 bucket

3. 白名单 / 染色​

手段场景
Header x-canary: 1测试、自动化
用户 ID 白名单员工 dogfood
地域 / 机房先单 AZ 灰度
App 版本号移动端强相关

4. 发布阶段流水线​

部署 v2 实例(0% 流量,健康检查通过)
↓
1% 真实流量 + 监控 15~30min
↓ 门禁通过
5% → 20% → 50% → 100%(每步可人工确认或自动)
↓ 任一步失败
权重 v2=0 或 scale v2=0(回滚)

关键: 每步之间要有 观测窗口 和 明确 promote/rollback 条件,不能一口气 100%。

控制面设计​

发布单模型​

字段说明
service哪个微服务
version_old / version_new镜像 tag / git sha
current_weight当前 v2 百分比
stage_index在第几档
statuspending / canarying / promoted / rolled_back
gates升档门禁表达式

配置下发​

控制面更新 weight
→ 写入 etcd / Nacos / K8s CRD
→ 网关 / Istio watch 生效(秒级)
→ 各节点 metric 带 version label

与 API 网关设计与实现 中 动态路由 + subset + weight 同一套机制。

自动门禁(进阶)​

指标典型规则
HTTP 5xx 率v2 不超过 v1 的 1.2 倍
P99 延迟v2 不超过 v1 + 50ms
业务下单成功率、支付失败率
样本量流量太小不自动判失败(防抖动)

不达标 → 自动 rollback + 告警 + 发布单标记 failed。

与 K8s / Mesh 的关系(点到为止)​

方案说明
Deployment 滚动默认替换,非精细比例;快但不如金丝雀细
Argo Rollouts原生 Canary 步骤、分析、回滚
Istio + FlaggerVirtualService 权重 + Prometheus 分析
Spinnaker多阶段 pipeline

面试可说:精细比例用 Mesh/网关权重;简单场景滚动够用。

数据与兼容性(必提)​

风险做法
v1/v2 同时在线API 向后兼容;删字段用新版本号
DB schema 变更Expand-Contract:先加列 → 双写/兼容读 → 再删旧列
缓存 key含版本或 schema 无关
消息格式消费者兼容新旧 event

灰度期间 两版本共享同一 DB 是常态,schema 必须向前兼容。

回滚​

方式速度说明
权重 → 0%秒级最快,v2 实例可保留排查
Scale v2 → 0分钟级彻底摘流量
蓝绿切回秒级整环境切换
重新部署旧镜像较慢最后手段

回滚按钮要在发布平台 一键可用,且演练过。

与功能开关的区别​

灰度发布Feature Flag
切什么部署实例 / 版本代码分支逻辑
粒度流量百分比用户/租户/随机
典型新版本整体行为单功能试运行

生产常 两者结合:新版本部署 5% 流量,功能开关再控新逻辑是否启用。

常见坑​

坑说明
无按版本监控看不出 v2 是否更差
权重变但缓存/CDN 未变客户端仍打旧逻辑
样本不足就升档1% 流量 5xx 波动大,误 rollback 或误 promote
schema 不兼容v2 读 v1 写崩
只灰度 API 不灰度 Job离线任务/schema 漏改

面试参考答法(90 秒)​

灰度发布我会做控制面、流量调度层和观测门禁三块。

发布时 v1、v2 同时注册,网关或 Service Mesh 按权重把流量分到不同 subset。逐步切换用阶段配置,比如 1%、5%、20%、50%、100%,每步观察错误率和 P99;用户维度用 hash(user_id)%100 保证粘性,测试账号可白名单染色。

控制面管理发布单和权重,配置推 etcd,网关 watch 热更新。监控按 version 标签对比,超阈值自动回滚权重到 0。同时要 API 和数据库向前兼容,因为两版本长期并存。回滚优先调权重,比重新部署快。精细流量用 Istio/网关权重,简单场景可用 K8s 滚动或 Argo Rollouts。

延伸阅读​

篇关系
API 网关设计与实现权重路由、灰度 subset
限流熔断与降级异常时熔断、降级
分布式系统基础多版本并存、一致性
API 设计与 HTTP 实践版本兼容

面试速记​

  1. 模式: 金丝雀 = 新旧并存 + 渐进权重;区别于蓝绿、滚动。
  2. 切流: 权重随机 / hash 用户 / 白名单 Header;网关或 Mesh 执行。
  3. 阶段: 1→5→20→50→100,每步观测 + 门禁 promote/rollback。
  4. 控制面: 发布单 + 配置中心 + 按 version 监控。
  5. 必提: DB/API 向前兼容;一键回滚权重归零。