bigywater.tech
微服务 · 32

金丝雀与蓝绿发布:流量比例、观察窗口与切换窗口

金丝雀每个阶段该放多少流量、观察多久?蓝绿切换会不会丢请求?旧版本什么时候才能关?这篇用 nginx 1.31.6 的 reload 做真实的分阶段放量和切换,再用二项分布算发现概率。

25%
5% 错误率的金丝雀、每阶段 2 秒 200 个请求/秒、错误 ≥ 5 且 ≥ 2% 就回滚时,4 次实验都是在这个阶段才发现
0.0% 对 87.4%
总请求率 50/s、金丝雀 1% 比例时,观察 10 s(5 个请求)与 300 s(150 个请求)的发现概率(二项分布计算)
3 / 1200
蓝绿切换后立刻 kill 旧版本时,在途请求失败的数量(保持旧版本运行是 0)

分阶段放量

实测 · 本机执行输出
  重复 | 各阶段 canary 收到的请求数 / 其中的错误数                  | 结果          | 用户一共看到的 503
  ---+---------------------------------------------+-------------+------------
  1  | 1%:5个请求/0个错 → 5%:20个请求/4个错 → 25%:80个请求/6个错  | 25% 阶段发现并回滚 | 10         
  2  | 1%:2个请求/0个错 → 5%:26个请求/2个错 → 25%:111个请求/7个错 | 25% 阶段发现并回滚 | 9          
  3  | 1%:5个请求/0个错 → 5%:17个请求/1个错 → 25%:115个请求/8个错 | 25% 阶段发现并回滚 | 9          
  4  | 1%:5个请求/0个错 → 5%:17个请求/0个错 → 25%:99个请求/7个错  | 25% 阶段发现并回滚 | 7          
  1% 阶段 canary 只收到几个请求,5% 的错误率几乎肯定一个错误都没有;错误要攒够 5 个才报警,所以通常要到 25% 阶段才发现。越早放大比例,发现越快,但出事时受影响的用户也越多

小比例阶段攒不够错误,要到足够的比例才发现;放大越早发现越快,受影响的用户越多。

观察窗口

实测 · 本机执行输出
  总请求率   | canary 比例 | 观察 10 s           | 观察 60 s            | 观察 300 s          
  -------+-----------+-------------------+--------------------+-------------------
  50/s   | 1%        | 5 个请求 · 0.0%      | 30 个请求 · 1.6%      | 150 个请求 · 87.4%   
  50/s   | 5%        | 25 个请求 · 0.7%     | 150 个请求 · 87.4%    | 750 个请求 · 100.0%  
  50/s   | 25%       | 125 个请求 · 75.4%   | 750 个请求 · 100.0%   | 3750 个请求 · 100.0% 
  200/s  | 1%        | 20 个请求 · 0.3%     | 120 个请求 · 72.2%    | 600 个请求 · 100.0%  
  200/s  | 5%        | 100 个请求 · 56.4%   | 600 个请求 · 100.0%   | 3000 个请求 · 100.0% 
  200/s  | 25%       | 500 个请求 · 100.0%  | 3000 个请求 · 100.0%  | 15000 个请求 · 100.0%
  1000/s | 1%        | 100 个请求 · 56.4%   | 600 个请求 · 100.0%   | 3000 个请求 · 100.0% 
  1000/s | 5%        | 500 个请求 · 100.0%  | 3000 个请求 · 100.0%  | 15000 个请求 · 100.0%
  1000/s | 25%       | 2500 个请求 · 100.0% | 15000 个请求 · 100.0% | 75000 个请求 · 100.0%
  需要的是 canary 本身收到的请求数,而不是总流量:总请求率低、比例小,就要观察更久;低流量的服务做金丝雀,窗口要按“攒够多少个请求”来定,而不是固定几分钟

按 canary 自己收到的请求数来定窗口,而不是固定几分钟。

蓝绿切换

实测 · 本机执行输出
  做法                           | 错误数 / 请求数 | 混合窗口(第一个 green 应答到最后一个 blue 应答) | 从 reload 完成到第一个 green 应答
  -----------------------------+-----------+---------------------------------+-------------------------
  (a) reload 后保持 blue 运行       | 0 / 1200  | 75 ms                           | 2 ms                    
  (b) reload 后立刻 kill blue     | 3 / 1200  | 没有重叠                            | 4 ms                    
  (c) 同 (b),到后端用 keepalive 长连接 | 2 / 1200  | 没有重叠                            | 8 ms                    
  nginx reload 之后,新的 worker 立刻用新配置接新连接,旧 worker 继续处理已经在它手上的请求和长连接直到处理完;所以 blue 要等旧 worker 把在途请求处理完再下线,立刻 kill 会让还在旧 worker 上的在途请求失败

reload 后新旧 worker 并存,旧版本要等在途请求处理完再下线。

分步演示

金丝雀与蓝绿发布
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Python 3.14.8 / Go / nginx / Envoy / etcd / Consul / Nacos / OpenTelemetry / Prometheus(按各篇注明用到哪些及版本);所有服务都是本机自己起的进程,端口 9150 以上,只监听 127.0.0.1,不连任何外部服务,不碰本机已有的实例;故障用 kill -9 进程、让连接断开或在代码里注入延迟与错误来制造;计时用 time.perf_counter,数字每次运行会有小幅抖动。nginx 是 Homebrew 的 1.31.6,用改配置加 reload 来放量与切换;canary / stable 后端是本进程里的 Python 服务(canary 用带种子的随机数按 5% 返回 503);蓝绿的 blue / green 是独立的 Python 进程(vtmp/v20/backend.py),用 kill() 关掉;第二节是二项分布计算,不是实测;第一节只重复了 4 次
    • 没有验证:真正的发布工具(Argo Rollouts、Flagger)的分析与自动回滚策略;用基线错误率做统计检验(这里用了固定阈值);多实例灰度、按用户粘性的灰度(见第 31 篇);数据库 schema 与蓝绿的兼容;长连接(WebSocket)在切换时的处理
    京ICP备2026067502号-1京公网安备11010502063487号