假设你是一座城市的交通局长。城市里唯一一座老桥已经服役三年,它就是正在线上运行的旧版模型。你刚刚验收了一座崭新的姊妹桥——刚训练完成、离线指标亮眼的新版模型。现在最棘手的问题是:怎样把桥上川流不息的车辆(线上请求)从老桥安全地引到新桥,而不让整座城市陷入瘫痪? 交通工程里其实早有一套成熟的“车流切换”工具箱:蓝绿部署,相当于在一个夜深人静的凌晨,把路牌瞬间一拨,所有车流整体改道新桥;金丝雀发布,是先在桥头放行 5% 的车试跑,确认没有坑再逐步放行更多;影子流量,则像派一支“隐形车队”——真实车辆照常走老桥,同时让同样多的车在新桥上平行跑一遍,只记录数据、不参与通行。而 SLO 门控,就是站在桥头的安全监测站:只有事故率、通行时间等指标达标,才允许放行下一批车。这篇文章,就是带你把这座“桥”的交通指挥系统完整搭建起来。
掌握流量路由与切换,你就能在模型上线时把事故影响从“全城瘫痪”压缩到“几条车道”,这是 MLOps 工程师最核心的线上风险管理能力。
目录
可视化演示
本节配有交互动效(进入视口后自动加载,约 3KB)。
流量路由:指挥中心的那张路牌
交通指挥中心的显示大屏上,每一块路牌都代表着车流的一个去向。老桥和新桥都真实存在,但车往哪边走,全看路牌的指向和放行的比例——这块路牌,就是流量路由。在模型上线这场“换桥工程”里,它决定了每个线上请求交给哪个版本的模型处理。
模型部署中的流量路由,本质上是一个“分流执行器”。路由控制器维护一份权重配置:old_weight 与 new_weight 之和恒等于 100%。权重一变,流量分配立即改变,整个过程不需要重启任何服务,就像路牌角度微调半度,桥上几十条车道的流向就此改变。这解决了模型上线最核心的矛盾:新版本必须接受真实流量的检验,但又不能拿全部用户冒险。
为了量化“切到新版本的比例”,我们定义新版本在时刻 $t$ 承接的流量占比为 $r(t)$:
路牌微调半度,城市车流就换了方向。所有上线策略——蓝绿、金丝雀、影子——本质上都是 $r(t)$ 随时间变化的不同曲线。理解了这张路牌,你就握住了整个模型部署的“方向盘”。
- 分子 Q_new(t)单位时间内被路由到新版本的请求数量,由路由权重直接决定。
- 分母总流量新旧两个版本在时刻 $t$ 收到的请求量之和,等于系统总请求量。
- 占比 r(t)取值在 0 到 1 之间,0 表示全部走老版本,1 表示全部走新版本,中间值表示按比例分流。
蓝绿部署:凌晨的瞬间改道
最痛快的交通局长会这样干:老桥一边,新桥一边,两座桥都提前点亮路灯、画好标线。凌晨三点车最少时,指挥中心一键拨动路牌,所有车流瞬间改道新桥。这就是蓝绿部署——切换只在几秒内完成,快得让人几乎感觉不到变化。
蓝绿部署维护两套完全相同的生产环境:蓝环境跑老版本,绿环境跑新版本。发布前,团队在绿环境完成全部验证,随后通过负载均衡器或 API 网关把流量一次性切到绿环境。正因为两套环境始终在跑,切换只是一次路由配置的变更,不涉及服务重启,天然支持“一键回滚”:路牌再拨回去,几秒内车流又回到蓝环境。
用阶跃函数可以精确描述这种“瞬间全量”的切换方式:
蓝绿部署的代价,是两座桥都得常年养护——双倍的机器、双倍的运维。对资源紧张的小团队,这笔“养桥费”可能比事故本身更肉疼。所以它更适合资源充裕、追求极致切换速度的场景。
- 切换前阶段在切换时刻 $t_{\text{switch}}$ 之前,全部流量留在蓝环境,绿环境处于就绪状态但零流量。
- 切换后阶段到达切换时刻,$r(t)$ 直接跳到 1,所有请求进入绿环境。
- 阶跃跳变性质$r(t)$ 从 0 到 1 没有中间值,风险集中在一个瞬间,回滚同理——再次翻转即可。
金丝雀发布:先放一队探路车
谨慎的交通局长会选择另一种方式:凌晨先放五辆出租车上新桥跑,盯着它们的位置和路况,确认安全后再放 30%、50%、80%,最后才全量放行。早年矿工下井会带一只金丝雀,用它探测瓦斯浓度;我们把这种“用小代价探测大风险”的思路搬到了模型上线里——这就是金丝雀发布。
金丝雀发布让新版本先承接少量真实流量(通常是 5%~10%),同时实时对比新旧版本的延迟、错误率、业务转化指标。每到一个放量节点,先观察一段时间,SLO 达标再继续放大比例;一旦不达标,立即把金丝雀流量撤回,事故半径始终被锁在很小的范围里。它不是“随机放点流量碰运气”,而是“放量 → 观察 → 验证 → 再放量”的受控闭环。
金丝雀的放量过程可以用阶梯函数描述:
金丝雀的优势是每次只让一小批车探路,事故半径被锁在 10% 以内;代价是整个过程可能持续几小时甚至几天。它是典型的“用时间换安全”,适合核心链路和高价值模型。
- 初始放量 r_start通常从 10% 起步,太小没有统计意义,太大则风险失控。
- 观察窗口 T_ramp每一档之间的等待时间,用来收集足够样本评估新版本的 SLO。
- 阶梯档位集合放量比例按 10% → 30% → 50% → 100% 逐级递增,而不是连续爬坡。
影子流量:一支看不见的车队
交通局长还有一招:派一支隐形车队——真实车辆照常走老桥,同时让完全相同的车流在新桥上平行跑一遍,但新桥的通行结果不对外发布,只记录数据供分析。这就是影子流量,一种“零感知”的试运行方式。
影子流量把线上真实请求复制一份送给新版本,新版本照常完成推理,但结果不返回给用户,只用于对比分析。它的核心理念是“零风险试运行”:线上用户体验完全不变,新版本却在真实流量分布下接受全面检验。对于风控、推荐这类对输出质量极其敏感的模型,影子流量是在放量之前的最佳体检手段。
新旧版本的行为差异可以用平均绝对误差来量化:
注意,隐形车队也要烧油——影子流量会把计算成本推高接近一倍。它适合在真正放量前做一次“全真流量压力测试”,用资源换安全,而不是长期运行的常态方案。
- 真实请求 x从线上复制而来的真实用户请求,保证影子流量与线上分布完全一致。
- 影子推理结果新模型在影子环境中对请求 $x$ 的推理输出,只记录不返回。
- 行为差异 Δ在 $N$ 个请求上,新旧版本输出差的绝对值取平均,差异过大说明新版本行为偏离线上预期。
SLO 门控:桥头的安全监测站
无论金丝雀还是蓝绿,放行多少车都不能拍脑袋。桥头必须有一座安全监测站,实时盯着事故率、平均通行时间、最长通行时间等指标——这些指标在工程上称为 SLO(服务等级目标)。它是“桥能不能继续放车”的客观标尺。
SLO 门控把“能不能放更多流量”的判断自动化。系统持续统计新版本的延迟分位数、错误率、可用性,只有当所有指标都满足预设阈值,晋升流程才继续;任何一项指标跌破红线,立即停止放量或触发回滚。这相当于给自动晋升装上了一个“一票否决”的安全阀,让 10% → 100% 的放量过程不再依赖人工盯屏。
晋升条件可以用逻辑与表达:
有了安全监测站,金丝雀的每一档放量都由数据说话。自动晋升流程从 10% 到 100% 全程无需人工,只有异常时才拉响警报——这正是 MLOps 追求的“可信任的自动化”。
- 指标集合 M_i第 $i$ 个 SLO 指标,例如 P95 延迟、错误率、可用性等线上运行指标。
- 阈值比较每个指标都必须达到对应阈值,如 P95 延迟低于 200ms、错误率小于 0.1%。
- 逻辑与门控$\bigwedge$ 表示“全部满足”,任何一个指标不达标,整体门控就不通过。
- 晋升决定Promote 为真,自动把流量扩到下一档;为假则保持或回滚,只有异常时人工介入兜底。
策略对比与选型:什么桥用什么方案
不是所有桥都适合同一种改道方案。城市主干道的桥和景区小桥,施工方案完全不同;流量切换策略的选型,本质上也是在风险、成本、速度三个维度之间做权衡。
蓝绿部署风险集中但切换最快,适合资源充裕、能接受“瞬时全量”的服务;金丝雀发布风险分散但耗时较长,适合核心链路和高价值模型;影子流量成本最高但最安全,适合上线前的行为校验。三者并非互斥,实际生产中常组合使用:先用影子流量验证行为一致性,再用金丝雀渐进放量,最后用蓝绿的快速回滚能力兜底。
选型时,团队可以给每个策略计算一个综合评分:
回到交通局长的视角:城市道路千差万别,没有绝对最优的方案,只有是否匹配当下的车流特征。掌握三种策略与 SLO 门控,你就真正握住了模型上线的方向盘——知道何时该瞬间改道,何时该放几只金丝雀探路,何时该派一支影子车队提前体检。
- 速度收益 Speed_k策略 $k$ 完成全量切换的速度,速度越快收益越高,蓝绿部署在此项得分最高。
- 风险损失 Risk_k单次发布事故的期望损失,与风险暴露时间、影响范围正相关。
- 资源成本 Cost_k额外环境常驻带来的开销,蓝绿部署在此项扣分最多。
- 综合评分 Score_k$w_1, w_2, w_3$ 是团队根据业务容忍度设定的权重,取分最高的策略或组合。
AI 应用场景
大促前推荐模型的金丝雀灰度
阶段:模型部署
解决的问题:大促前升级推荐模型,若直接全量上线出现抖动,会直接拉低整个大促的转化率。传统做法是“熬夜等到凌晨一把梭”,出了问题只能全员回滚。金丝雀发布配合 SLO 门控,让风险在 5% 流量内先暴露。
具体案例:某电商平台在大促前用流量路由把新推荐模型逐步放量:先切 5%,SLO 门控实时监控 P95 延迟和点击率,达标后自动扩到 30%、60%、100%。深夜高峰段新版 P95 超时,门控自动回滚到上一档,避免了一次全站事故。
银行风控模型的影子流量验证
阶段:模型部署
解决的问题:风控模型的误杀率直接关系资金风险与用户体验,新模型上线前必须验证其在真实交易分布上的表现。影子流量让新模型在真实交易上并行运行而不影响线上决策,把“行为校验”前置到放量之前。
具体案例:某银行反欺诈团队把新模型接入影子流量,与线上老模型并行跑了一周,发现新模型对某类正常交易误拒率偏高,及时调整阈值后才进入金丝雀放量,避免了误杀正常用户带来的投诉潮。
智能客服系统的蓝绿快速切换
阶段:模型部署
解决的问题:客服机器人迭代频繁,既要快速上线又必须随时可回滚。蓝绿部署让新版本全量切换后若投诉率上升,运维只需一键把流量切回蓝环境,整个回滚在分钟级完成。
具体案例:某互联网公司的智能客服系统采用蓝绿部署,新版对话模型上线后意图识别准确率波动,监控发现后立即切回蓝环境,随后在绿环境复现问题、修复模型,整个过程用户几乎无感知。
Python 演示
"""Traffic router demo: canary release with SLO-gated auto promotion."""import random class TrafficRouter: """Route requests to old/new model versions by weight.""" def __init__(self, new_weight=0.0): self.new_weight = new_weight # share of traffic to the new version self.old_weight = 1.0 - new_weight # share of traffic to the old version self.req_count = {"old": 0, "new": 0} self.err_count = {"old": 0, "new": 0} def route(self, request_id): """Send one request to a version and simulate its outcome.""" r = random.random() target = "new" if r < self.new_weight else "old" self.req_count[target] += 1 err_rate = 0.01 if target == "new" else 0.005 ok = random.random() >= err_rate if not ok: self.err_count[target] += 1 return target, ok def slo_passed(self, max_err_rate=0.008): """SLO gate: the new version must keep its error rate low.""" n = self.req_count["new"] if n == 0: return False return self.err_count["new"] / n < max_err_rate def canary_release(router, stages=(0.1, 0.3, 0.5, 1.0), burn_in=300): """Promote new version stage by stage; roll back if SLO fails.""" for stage in stages: router.new_weight = stage router.old_weight = 1.0 - stage print("shift %.0f%% traffic to new version" % (stage * 100)) for _ in range(burn_in): router.route(random.randint(1, 10**6)) if not router.slo_passed(): router.new_weight = 0.0 router.old_weight = 1.0 print("SLO failed, roll back to 0%") return False err = router.err_count["new"] / router.req_count["new"] print(" new version error rate = %.4f, gate passed" % err) print("all traffic is on the new version") return True if __name__ == "__main__": router = TrafficRouter() ok = canary_release(router) print("released:", ok, "| final new_weight =", router.new_weight)
target = "new" if r < self.new_weight else "old"路由的核心逻辑:随机数落在哪个权重区间,请求就去哪个版本err_rate = 0.01 if target == "new" else 0.005模拟新版本初始错误率略高于老版本,给门控创造“拦截”的场景return self.err_count["new"] / n < max_err_rateSLO 门控判断:新版本错误率低于阈值才算达标router.new_weight = stage每一档放量只是改一个权重数字,服务无需重启if not router.slo_passed():任何一档不达标立即回滚到 0%,体现“小步快跑、快速撤退”
常见误区
误区蓝绿部署听起来最简单,直接把流量切过去就行,应该是最省钱的方式。
正解蓝绿部署需要两套完全相同的生产环境长期并行,意味着双倍的机器、双倍的运维成本。而且发布完成后旧环境还要保留一段时间以应对回滚,成本并不会立即降下来。真正省钱的是金丝雀——新版本只需少量实例先承接部分流量,验证通过后再逐步扩容。
为何常见:只看到切换动作简单,忽略了背后“两座桥常年养护”的环境成本。
误区金丝雀发布不就是把 10% 的请求随机打到新版本上吗?还有什么复杂的?
正解金丝雀的核心不是“随机放量”,而是“放量 → 观察 → 验证 → 再放量”的受控闭环。它需要 SLO 门控、指标对比、自动回滚机制配合,否则 10% 的流量放出去也可能酿成事故。随机打流量只是手段,受控验证才是目的。
为何常见:把一套工程体系误解为一条配置命令,忽略了它背后完整的观测与决策链路。
误区影子流量既然不返回结果给用户,那是不是就等于免费跑?
正解影子流量要把线上请求完整复制一份送进新版本,计算吞吐、内存、带宽都是真实消耗,总成本接近双倍。大量影子请求还可能压垮影子环境,造成延迟放大影响对比结果。影子流量是“用资源换安全”,绝不是零成本。
为何常见:只关注用户侧无感知,忽略了资源侧的真实开销——隐形车队也要烧油。
误区SLO 达标不达标,看看平均响应时间不就行了?
正解平均指标会被少数慢请求“平均掉”。真实 SLO 更关注分位数和错误率,例如“P95 延迟 < 200ms 且错误率 < 0.1%”。如果 95% 的请求都很快、只有 5% 卡死,平均值依然好看,但用户体验已经崩溃。门控必须盯住长尾和异常,而不是均值。
为何常见:习惯了离线评估的均值思维,不理解线上长尾请求对体验的破坏力。
误区流量全部切到新版本,发布不就结束了吗?可以安心睡大觉了。
正解全量切换只是新版本开始承担全部流量的起点,还需持续监控 SLO 一段时间,并保留快速回滚通道。很多模型问题在低流量时隐藏、在高流量下才暴露——比如缓存击穿、资源争抢。发布完成不等于验证完成。
为何常见:把部署当终点,忽略了部署后验证的闭环,这正是事故高发的窗口期。
面试题
Q1. 蓝绿部署中被称为“绿”的环境通常是?
- A.正在线服务的旧版本
- B.测试阶段的临时版本
- C.待切换上线的新版本← 正确答案
- D.已经回滚的废弃版本
答案:C。蓝绿部署中“蓝”指当前在线的旧版本,“绿”指待切换上线的新版本,两者是代号而非颜色语义。切换时把流量从蓝环境整体切到绿环境。测试环境和回滚版本都不属于“绿”的定义。
Q2. 金丝雀发布相对蓝绿部署的最大优势是?
- A.风险暴露范围更加可控← 正确答案
- B.切换速度能达到秒级
- C.完全不需要额外资源
- D.能保证模型零错误
答案:A。金丝雀发布先让新版本承接少量流量,风险暴露范围被限制在放量比例内,相比蓝绿“瞬间全量”的方式,核心优势在于风险可控、可观测、可小粒度回滚。切换速度反而是金丝雀的劣势,它也不可能保证零错误。
Q3. 影子流量的典型特征包括?
- A.把真实请求复制给新版本← 正确答案
- B.新版本响应直接返回用户
- C.响应仅供内部对比分析← 正确答案
- D.不影响线上用户的决策← 正确答案
答案:ACD。影子流量复制真实请求进入影子环境,新版本照常推理但响应不返回用户,只用于内部对比,因此选 A、C、D。B 说响应直接返回用户,与影子流量“只记录不返回”的定义完全相反,线上用户的决策仍由老版本决定。
Q4. SLO 门控自动晋升的核心逻辑是?
- A.等待人工逐项审批完成
- B.无论指标好坏都全量切
- C.指标达标才扩大新版流量← 正确答案
- D.只统计一次模型准确率
答案:C。SLO 门控的逻辑是“指标达标才放量”:新版本在每一档流量下运行,系统实时统计延迟、错误率等指标,全部满足阈值才晋升下一档,否则停止或回滚。它不依赖人工审批,也不是无条件切换,更不是只看一次离线准确率。
Q5. 哪种发布方式需要两套完整环境常驻?
- A.蓝绿部署需要两套环境← 正确答案
- B.金丝雀发布需要两套环境
- C.影子流量需要两套环境
- D.滚动更新需要两套环境
答案:A。蓝绿部署要求蓝、绿两套完全相同的生产环境长期并行,这是它成本高的根本原因。金丝雀发布只需新版本少量实例,影子流量只需影子环境,滚动更新则是在一套环境内逐个替换实例,都不需要完整的两套环境常驻。
Q6. 实现金丝雀发布需要哪些能力?
- A.流量按比例灰度分配← 正确答案
- B.实时观测线上指标← 正确答案
- C.支持快速版本回滚← 正确答案
- D.必须停机重新部署
答案:ABC。金丝雀发布的前提是按比例分配流量(灰度)、实时观测线上指标、快速回滚,三者缺一不可。停机重新部署与金丝雀的“热切换”理念完全相反——金丝雀追求的是不停机地小范围试错。
Q7. 蓝绿部署资源成本偏高的根本原因是?
- A.数据标注要重复进行
- B.模型训练要多做一轮
- C.新旧两套环境长期并存← 正确答案
- D.监控系统要额外搭建
答案:C。蓝绿部署成本高的根本原因是新旧两套环境长期并存,为了随时回滚,旧环境切换后还要保留一段时间,机器、存储、运维全部双份。训练轮次、数据标注、监控搭建都不是蓝绿特有的成本来源。
Q8. 支付核心系统升级风控模型,最稳妥的做法是?
- A.凌晨直接做蓝绿全量切换
- B.只靠离线指标就快速上线
- C.新旧两版随机均匀地分流
- D.影子验证后金丝雀式放量← 正确答案
答案:D。支付核心系统对风险极度敏感,最稳妥的组合是先用影子流量在真实交易上验证新模型行为(零线上影响),再以金丝雀小比例放量并用 SLO 门控自动决策。直接蓝绿或随机分流都放大了风险,只看离线指标则忽略了线上分布差异。
Q9. 适合作为 SLO 门控的指标是?
- A.请求延迟 P95 分位数← 正确答案
- B.线上请求错误率← 正确答案
- C.离线训练损失值
- D.服务可用性百分比← 正确答案
答案:ABD。SLO 门控监控的是线上运行质量,P95 延迟、错误率、可用性都直接反映服务健康,适合作为晋升条件。离线训练损失是训练阶段的指标,与线上服务质量没有直接关系,不能作为线上门控依据。
Q10. 流量路由控制器的主要职责是?
- A.训练并保存新模型参数
- B.清洗并标注原始训练数据
- C.按策略分流请求到版本← 正确答案
- D.生成服务告警通知消息
答案:C。路由控制器按配置的权重把请求分发到不同模型版本,是“分流”的执行者——就像交通指挥中心拨动路牌。训练参数、清洗数据、生成告警都不是它的职责,它们属于训练、数据处理和监控系统的范围。