蓝绿/灰度/金丝雀发布:流量切换、回滚、A/B 测试

puml.online

上线新版本不是「全量推送」那么简单——四种发布策略各有取舍。这篇是蓝绿 / 灰度 / 金丝雀 / A/B 测试的架构、流量切换机制、回滚方案,以及 Feature Flag、Argo Rollouts、LaunchDarkly 工具实战。

四种发布策略对比

策略 流量切换 回滚速度 风险 适用
蓝绿 100% 一次性 秒级(切回蓝) 大版本
金丝雀 1% → 5% → 25% → 100% 分钟级(切流量) 通用
灰度(Feature Flag) 按用户/特征分流 秒级(改 flag) 新功能
A/B 测试 按用户分组对比 改动大 实验

策略 1:蓝绿发布(Blue/Green)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
@startuml
title "Blue/Green Deployment"

actor "Users" as Users
participant "Load Balancer" as LB
participant "Blue Env\n(v1.0)" as Blue
participant "Green Env\n(v2.0)" as Green
database "Blue DB" as BlueDB
database "Green DB" as GreenDB

== 部署 v2.0 到 Green ==
Users -> LB : ① 100% 流量
LB -> Blue : ② 路由到 Blue
Blue -> BlueDB : ③ 读 v1.0
BlueDB --> Blue : ④ 数据

note over Green
部署 v2.0 到 Green
不接流量
内部测试
end note

Green -> GreenDB : ⑤ 数据迁移 / 双写测试

note over LB : 切换流量
LB -> Green : ⑥ 100% 流量切到 Green
Green -> GreenDB : ⑦ 读 v2.0

== 回滚(秒级) ==
LB -> Blue : ⑧ 一秒切回 Blue(紧急情况)

note right of LB
DNS / nginx upstream /
k8s service selector
一行命令切换
end note

@enduml

蓝绿部署要点:

  • 两套完整环境 — 资源 ×2
  • 共享数据库 — 两版本兼容同一 schema
  • 切换瞬时 — DNS / LB 一行命令
  • 回滚秒级 — 切回蓝即可

策略 2:金丝雀发布(Canary)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
@startuml
title "Canary Deployment - Gradual Rollout"

actor "Users" as Users
participant "Load Balancer\n(istio / nginx)" as LB
participant "v1.0 (95% traffic)" as V1
participant "v2.0 (5% traffic)" as V2
database "DB" as DB

== Step 1: 1% canary ==
Users -> LB : ① 1000 用户访问
LB -> V2 : ② 1% → 10 用户到 v2.0
LB -> V1 : ③ 99% → 990 用户到 v1.0

note over V2
监控 v2.0:
- 错误率 < 1%?
- p99 延迟 < 500ms?
- CPU 正常?
end note

V2 -> DB : ④ 读写
V1 -> DB : ④ 读写
DB --> V2 : ⑤ 数据
DB --> V1 : ⑤ 数据

== Step 2: 增加流量 ==
LB -> V2 : ⑥ 5% (50 用户)
LB -> V1 : ⑦ 95% (950 用户)

note over LB
监控稳定持续 10 分钟
流量提升到 25%
end note

== Step 3: 25% canary ==
LB -> V2 : ⑧ 25% (250 用户)
LB -> V1 : ⑨ 75% (750 用户)

== Step 4: 100% 全量 ==
LB -> V2 : ⑩ 100% 切到 v2.0
V1 --> [*] : ⑪ 旧版本下线

note over LB
异常时:
LB -> V1 : 紧急切回 100% v1.0
秒级回滚
end note

@enduml

金丝雀关键:

  • 渐进流量提升 — 1% → 5% → 25% → 50% → 100%
  • 监控对比 — v1.0 vs v2.0 错误率/延迟/CPU
  • 快速回滚 — 切流量即可,不动 pod

策略 3:Feature Flag(灰度)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
@startuml
title "Feature Flag Toggling"

actor "User A" as UA
actor "User B" as UB
actor "User C" as UC

participant "App" as App
participant "Feature Flag Service" as FF
database "Flag Config" as Config

UA -> App : ① 请求
UB -> App : ② 请求
UC -> App : ③ 请求

App -> FF : ④ evaluate "new_checkout"
FF -> Config : ⑤ 查规则

note right of FF
规则:
- User A,B → enabled
- User C → disabled
- 灰度 50%
end note

Config --> FF : ⑥ 规则

FF --> App : ⑦ User A: enabled
FF --> App : ⑧ User B: enabled
FF --> App : ⑨ User C: disabled

App -> App : ⑩ User A 走新 checkout (v2 代码路径)
App -> App : ⑪ User B 走新 checkout
App -> App : ⑫ User C 走老 checkout (v1)

@enduml

Feature Flag 类型:

  • Boolean flag — 全开 / 全关
  • 用户白名单 — 内部员工 / beta 用户
  • 百分比灰度 — 50% 用户
  • 按特征 — 国家 / 设备 / 订阅等级
  • A/B 实验 — 不同变体

LaunchDarkly / Unleash 实战:

1
2
3
4
5
6
7
8
9
10
11
12
const LaunchDarkly = require('ldclient-node');
const ldClient = LaunchDarkly.init('sdk-key-xxx');

ldClient.identify({ key: userId, email: user.email });

const enabled = await ldClient.variation('new-checkout', user, false);

if (enabled) {
return newCheckoutFlow(cart);
} else {
return oldCheckoutFlow(cart);
}

策略 4:A/B 测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@startuml
title "A/B Test Experiment Flow"

actor "User" as U
participant "App" as App
participant "Experiment Service" as Exp
database "Experiment Config" as Conf
participant "Analytics" as Ana

U -> App : ① 访问
App -> Exp : ② get variant "checkout_color"
Exp -> Conf : ③ 查实验配置
note right
实验:
- 50% → variant A (蓝色按钮)
- 50% → variant B (绿色按钮)
跟踪指标:
- 点击率
- 转化率
end note
Conf --> Exp : ④ 规则
Exp --> App : ⑤ variant = "B"

App -> App : ⑥ 渲染绿色按钮 (variant B)
U -> App : ⑦ 点击绿色按钮
App -> Ana : ⑧ 事件 {variant:B, event:click}

note over Ana : 7 天后分析
Ana -> Ana : ⑨ 统计: B 转化率 +15% (p<0.01)

@enduml

A/B 测试要点:

  • 对照组 — variant A(原版)
  • 实验组 — variant B(新设计)
  • 样本量计算 — 要 p<0.05 显著性,需要足够流量
  • 单一变量 — 只改一个东西,否则归因不清
  • 跟踪指标 — 主指标 + 副指标 + 护栏指标

蓝绿 vs 金丝雀 vs Feature Flag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
@startuml
title "Strategy Selection Decision"

start

:新版本需要发布;

if (改动是否兼容数据库 schema)
if (兼容)
:继续;
else
:先做 schema 迁移(expand-migrate-contract);
end
end

:新功能 vs 性能修复?;

if (新功能)
if (用户范围)
if (内部测试)
:Feature Flag (白名单);
else if (5% 灰度)
:Feature Flag (5%);
else if (全量)
:Feature Flag (100%) + 直接发布;
end
end
else
if (高风险改动)
:蓝绿(测试完整流量);
else
:金丝雀(1% → 5% → 25% → 100%);
end
end

:监控指标稳定后完成;

stop

@enduml

Argo Rollouts 金丝雀实战

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# rollout.yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: user-service
spec:
replicas: 10
selector:
matchLabels:
app: user-service
strategy:
canary:
steps:
- setWeight: 5 # 5% 流量到 v2
- pause: {duration: 5m}
- setWeight: 25 # 25%
- pause: {duration: 5m}
- setWeight: 50
- pause: {duration: 10m}
- setWeight: 100 # 全量
- pause: {duration: 5m}
canaryService: user-service-canary
stableService: user-service-stable
trafficRouting:
istio:
virtualService:
name: user-service-vs
analysis:
templates:
- templateName: success-rate
- templateName: latency
startingStep: 2 # 从 25% 开始分析
args:
- name: service-name
value: user-service
template:
metadata:
labels:
app: user-service
spec:
containers:
- name: user-service
image: user-service:v2.0
---
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: success-rate
spec:
metrics:
- name: success-rate
interval: 30s
successCondition: result[0] >= 0.95
failureLimit: 3
provider:
prometheus:
address: https://prometheus.internal
query: |
sum(rate(http_requests_total{status!~"5..",service="user-service"}[5m]))
/
sum(rate(http_requests_total{service="user-service"}[5m]))

Argo Rollouts 行为:

  • 部署 v2 到 canary pod
  • 调整 Istio VirtualService 流量
  • 每步暂停 N 分钟
  • 跑 Prometheus 分析
  • 失败自动 abort,回滚到 v1
  • 成功自动 next step

数据库 schema 兼容性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
@startuml
title "Backward-Compatible Schema Migration"

database "DB v1.0" as V1
database "DB v1.5 (compatible)" as V15
database "DB v2.0" as V2

== Step 1: 添加新列(不删旧列) ==
V1 -> V15 : ① ALTER TABLE ADD COLUMN new_field VARCHAR(50)
note right
v1.0 应用: 读 old_field
v2.0 应用: 读 new_field (fallback to old_field)
end note

== Step 2: 双写 ==
V15 -> V15 : ② 应用双写 old_field + new_field
note right
v2.0 写 new_field
旧应用仍读 old_field
end note

== Step 3: 回填 ==
V15 -> V15 : ③ UPDATE SET new_field = old_field
note right
历史数据 new_field 也填上
end note

== Step 4: 切换读取 ==
V15 -> V15 : ④ v2.0 读 new_field

== Step 5: 清理 ==
V15 -> V2 : ⑤ DROP COLUMN old_field
note right
安全删除,旧版本不再用
end note

@enduml

核心原则:永远先加后删——v2.0 部署时仍兼容 v1.0 的代码。

回滚决策树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
@startuml
title "Rollback Decision Tree"

start

:监控告警;

if (错误率 > 5%)
:立即回滚(蓝绿切回);
stop
elseif (错误率 1-5%)
:暂停灰度;
if (10 分钟内恢复)
:继续;
else
:回滚;
end
elseif (错误率 < 1% 但延迟高)
:检查是否有上游依赖问题;
if (上游问题)
:上游恢复后继续;
else
:暂停或回滚;
end
elseif (业务指标异常)
:检查是否实验组问题;
if (新版本引入)
:Feature Flag 关闭;
else
:不回滚;
end
end

stop

@enduml

实战踩坑

  • 数据库 schema 不兼容 — v2.0 部署时 v1.0 代码连不上。强制 expand-migrate-contract 流程
  • 金丝雀 pod 没接流量 — Istio VirtualService 没配对。canaryService / stableService 都要配
  • Feature Flag 没清理 — 100% 启用后 flag 还在代码里。定期审计 + 工具强制清理
  • A/B 测试样本不够 — 流量小,结果不显著。用 power analysis 算最低样本量
  • 回滚太慢 — 金丝雀每步手动操作。用 Argo Rollouts 自动回滚
  • 回滚导致数据不一致 — v2.0 写了数据,v1.0 读不到新字段。双写兼容期
  • 监控盲区 — 只看 HTTP 状态码,看不到业务错误。业务埋点 + 错误聚合
  • Feature Flag 服务挂了 — 整个 app 加载 flag 超时。fallback 到默认值 + 本地缓存

决策树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
要发布什么?
├─ 全量发布新版本 → 蓝绿(高风险) / 金丝雀(标准)
├─ 灰度新功能 → Feature Flag
├─ 实验验证 → A/B 测试
└─ 紧急修复 → 蓝绿 + 立即切回

风险等级?
├─ 低(纯前端 / 性能优化) → Feature Flag 直接启用
├─ 中(后端逻辑) → 金丝雀
└─ 高(数据库迁移 / 架构改动) → 蓝绿 + 完整测试

回滚要求?
├─ 秒级 → 蓝绿
├─ 分钟级 → 金丝雀 + 自动化
└─ 可延迟回滚 → Feature Flag(下次发布清理)

最小可行:Feature Flag (Unleash 自部署) + 金丝雀手动。生产级:Argo Rollouts + Prometheus 分析 + LaunchDarkly(商业)。

记住:没有零风险发布,只有低风险发布 + 快速回滚监控 + 自动化 + 数据兼容是三个核心。新版本上线当天盯监控 2 小时,别只发完就走。

  • 标题: 蓝绿/灰度/金丝雀发布:流量切换、回滚、A/B 测试
  • 作者: puml.online
  • 创建于 : 2026-07-30 18:15:00
  • 更新于 : 2026-08-14 21:34:29
  • 链接: https://puml.online/blog/plantuml-blue-green-canary/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。