腾讯云服务器灰度发布:蓝绿、金丝雀与回滚的工程做法
有个凌晨的发布我印象很深:新版本刚上五分钟,支付回调的成功率就往下掉,我做的第一件事不是回滚代码,而是把负载均衡上新机器那一组的权重改成 0,先把流量摘干净。灰度发布看着是一堆流程名词,本质只解决一个问题:让坏版本只影响一小部分用户,并且你能快到不心虚地把它切回去。 这篇不搭从零开始的 CI 流水线,只讲腾讯云服务器灰度发布在工程上真正要落地的几件事——策略怎么选、流量怎么切、新旧版本怎么兼容、回滚速度到底由什么决定。
四种发布策略:停机、滚动、蓝绿、金丝雀怎么选
先把几种常见策略摆清楚,它们的差别不在"先进程度",而在成本和对用户的影响。
停机发布最原始:停服务、更新、启动,期间不可用。适合内部系统、能接受维护窗口的业务。它的问题是"一停全停",回滚就是把旧版本再启回来,动作简单,但要承受第二次停机。
滚动发布逐批替换实例,始终有实例在服务,流量平滑,是很多团队默认的方式。它的隐患是同一时间新旧版本共存,接口和数据结构必须兼容;而且一旦新版本有共性问题,你已经在替换下一批了,回滚要再滚一遍,慢。
蓝绿发布维护两套完整环境,通过负载均衡或网关把流量整体从一组切到另一组。切得快、回滚也快,代价是资源翻倍——得有预算常备两套环境。
金丝雀发布先放一小部分流量到新版本,观察指标正常再逐步放大,把风险控制在最小范围,是目前对线上最友好的做法。它需要流量能按比例或按人群切分,以及可观测的指标做支撑。
在腾讯云上,这些策略的落地载体不同:传统部署多用云服务器 CVM 配合负载均衡 CLB;容器化则常用 TKE 的 Ingress 和 Service,按副本比例或请求头分流。选哪种不看谁时髦,看你能承受多大风险、愿意为"随时回退"付多少资源成本。还有一点容易被忽略:策略不是非此即彼,常见组合是"蓝绿打底、金丝雀放量"——先用一小部分真实流量验证新版本,指标稳定后再整体切组,低风险和快回滚兼得。
发布策略 流量切换方式 回滚动作 回滚耗时量级 额外资源成本 适用场景
停机发布 无,先停后起 重启旧版本 一次停机时长 无 内部系统、可接受维护窗口
滚动发布 逐批替换实例 反向滚动回旧版本 数分钟到十几分钟 低 无状态服务、常规迭代
蓝绿发布 负载均衡整体切组 流量切回原组 秒级到分钟级 高,需双份资源 核心链路、要求快速回滚
金丝雀发布 权重或网关按比例分流 权重调回 0 摘流 秒级 中 大多数面向用户的业务
影子流量 复制流量给新版本但不返回 直接停影子实例 秒级 中 上线前验证,不影响真实用户
流量怎么切:负载均衡权重、DNS 与网关的分工
流量切换是灰度的核心动作,腾讯云上主要有三条路:负载均衡权重、DNS、网关。
负载均衡权重最直接。在 CLB 上挂一个监听器,后端绑定两个服务器组(旧版本组、新版本组),把新版本组的权重从 0 逐步调到 10、50、100。灰度出事时最快的动作就是把新组权重调回 0,流量秒级脱离,这也是我最常用的一招。 前提是健康检查配置正确,否则权重还没调,探针先把新实例摘了。CLB 还支持按轮询或最小连接数调度,配合会话保持时要留意粘性对灰度比例的影响。
DNS 切换靠改解析记录生效,受 TTL 限制,分钟级甚至更慢,而且客户端 DNS 缓存不可控,切不干净也切不均匀。它更适合跨地域、跨集群级别的整体切换,不适合要求快速回滚的常规灰度。
网关分流最灵活。Nginx、腾讯云 API 网关或 Ingress 可以按请求头、Cookie、请求路径、用户 ID 哈希或百分比把流量导向不同版本。按用户维度分流能保证同一个用户始终进同一个版本,避免"刷新一次换一个后端"的体验灾难。
实操里三者常常组合:网关做细粒度灰度,CLB 权重做粗粒度放量与紧急摘流,DNS 只在机房级切换时才动用。
还有一个常被忽略的动作叫优雅下线:实例摘流之前先把连接排空,让正在处理的请求跑完再停。否则权重调到 0 的那一刻,老实例上正在进行的请求会被直接切断,用户看到零星报错——这些报错混进灰度指标里,会让人误判成新版本的问题。
会话与数据库的兼容:让新旧版本能共存
新旧版本同时在线的这段时间,兼容性是灰度能不能成立的前提。
先看会话。应用要尽量做成无状态,会话数据放 Redis 之类的共享存储,而不是各实例的本地内存。如果暂时做不到,就靠负载均衡的会话保持把同一用户钉在同一版本,但这会让灰度比例失真——被粘住的那批用户可能长期停在旧版本,观察不到新版本的真实表现。
再看数据结构。新版本写进去的数据,旧版本读到会不会崩?老版本写的缓存,新版本反序列化是否会失败?发布的前后兼容原则是只做加法、不做破坏性修改,让新旧版本在任何组合下都能读写同一份数据。 缓存 key 尽量带版本号,结构变更先双写、再切读、最后清理旧字段。消息队列的消费者也要兼容:新版本发出的消息,还在运行的旧版本消费者必须能处理,否则一个字段改名就能让队列堵住。
数据库是最硬的约束,它常常不可逆,放到下一节单独讲。
灰度批次、观察指标,以及回滚快慢取决于什么
灰度不是"上一次就完事",要有明确的批次和放行标准。
批次设计上,我习惯按 1% 到 10%、再到 50%、最后到 100% 走,每一档之间留出足够的观察窗口,至少覆盖一个业务高峰或一个完整的定时任务周期。只放量不观察,等于把"全量发布"拆成了几步做,没有意义。
观察指标要分层:技术层看错误率、P99 与 P95 延迟、QPS、实例 CPU 与内存、GC 停顿、连接数;业务层看下单成功率、支付回调成功率、关键接口转化率;日志层看异常栈和特定错误码是否新增。技术指标正常但业务指标掉了,同样是异常,别只盯着一块监控屏。观察窗口里还要固定一批对照数据:灰度 10% 的时候,同时看这 10% 和剩下 90% 的表现做对比,别只看整体均值——整体被稀释过,问题常常藏在平均值底下。
回滚速度快慢,取决于四个条件,缺一个都会拖后腿:旧版本实例是否还在(蓝绿天然留着,滚动要重新拉起)、数据库变更是否可逆、配置是否中心化能一键下发、流量能否在负载均衡或网关层一次摘干净。回滚预案要在发布前就写好并演练过,而不是出问题时现场讨论——现场讨论的每一分钟,都是用户在用坏版本。放量到 100% 之前,也给旧版本留一条随时能切回来的退路,直到下一个版本发布之前都别急着把旧环境销毁。
数据库不可回滚的坑与小团队的最小可行方案
数据库是灰度里最容易埋雷的地方,因为它往往不可回滚。
一个典型坑是"改字段"。如果新版本把某列改名或改类型,旧版本立刻读不到数据,灰度期间新旧并存就会互相打架。正确做法是先扩后收(expand-contract):先加新列、双写新旧列、把读切到新列、确认稳定后再删旧列,而删列这一步永远放到下一个发布周期,不和本次发布同批上线。加列时给默认值或允许 NULL,避免大表加非空列锁表。
第二个坑是数据回填。回填脚本要幂等、可重跑、分批执行,别一把梭更新整张表,既可能锁表,也可能把主从复制延迟拉高。回填和发布解耦,脚本独立执行,出问题能随时停下。
第三是删除类操作,灰度期绝对不能删还在被旧版本引用的字段、索引、消息类型。真正的删除动作要等到确认没有旧版本实例在线之后再做。
对小团队,我给的最小可行灰度方案是:一台 CLB 挂两组后端(旧组、新组),镜像按版本打 tag 并保留上一版;发布时新组权重从 0 逐步放量,监控盯错误率和 P99;数据库只做加法,破坏性变更单独排期;提前写好一键摘流和回滚脚本。流水线里只给高风险项设人工审批卡点——涉及数据库结构、涉及不可逆操作、涉及核心链路时卡一下,日常小改不必层层签字,否则大家只会想办法绕过流程。
另外,发布要和环境解耦:配置别硬编码在镜像里,用配置中心或环境变量注入,回滚时就不用重新构建镜像,切回去只要换一份配置。镜像按不可变原则打 tag、保留上一版,回滚才有东西可退;直接覆盖同一个 tag 的镜像,会让回滚变成无源之水。
FAQ
Q:灰度发布一定要有 Kubernetes 吗?
A:不一定。在腾讯云服务器上单机部署,用 CLB 挂两组后端、按权重切流量,就能实现基础灰度。容器只是让实例管理更省事,不是前置条件。
Q:新版本放量后指标正常,第二天却出问题,为什么?
A:短期指标会骗人。灰度观察窗口要覆盖一个完整的业务周期,含高峰和定时任务。定时任务、月底结算、批量对账这类低频逻辑,几分钟的观察窗口根本覆盖不到。
Q:数据库字段改名怎么灰度才安全?
A:不要直接改名。走先扩后收:加新列、双写、切读、稳定后删旧列,删除动作放到下一发布周期。让新旧版本在任何时刻都能读写同一份数据。
Q:回滚到底能多快?
A:取决于四件事是否都满足:旧版本实例还在、数据库变更可逆、配置能一键下发、流量能在负载均衡或网关层一次摘干净。任缺一个,回滚就会从"秒级摘流"退化成"重新发布"。
结语
灰度发布说到底是一套承认自己会犯错的工程纪律。给个能立刻落地的建议:下一个版本发布前,先把负载均衡上旧版本那一组后端留着别急着下线,准备好一条把新组权重调回 0 的命令,再把本次涉及的数据库变更过一遍——凡是要删字段、改类型、改索引的操作,全部挪到下一个发布周期。做到这三点,你的回滚速度就已经超过大多数团队了。如果你手上是几台腾讯云服务器、没有现成的发布系统,想低成本搭一套能灰度、能一键回滚的方案,可以找我们按你的实际流量和预算给个组合建议,云服务器 CVM 加负载均衡 CLB 就能起步。
如果需要更深入咨询了解可以联系全球代理上TG:jinniuge 他们在云平台领域有更专业的知识和建议,他们有国际阿里云,国际腾讯云,国际华为云,aws亚马逊,谷歌云一级代理的渠道,客服1V1服务,支持免实名、免备案、免绑卡。开通即享专属VIP优惠、充值秒到账、官网下单享双重售后支持。不懂找他们就对了。
3 .0
