如何设计一个灰度发布系统?如何控制流量逐步切换到新版本?
灰度发布(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 VirtualService | Istio 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 | 在第几档 |
status | pending / 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 + Flagger | VirtualService 权重 + 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 实践 | 版本兼容 |
面试速记
- 模式: 金丝雀 = 新旧并存 + 渐进权重;区别于蓝绿、滚动。
- 切流: 权重随机 / hash 用户 / 白名单 Header;网关或 Mesh 执行。
- 阶段: 1→5→20→50→100,每步观测 + 门禁 promote/rollback。
- 控制面: 发布单 + 配置中心 + 按 version 监控。
- 必提: DB/API 向前兼容;一键回滚权重归零。