Skip to content

灰度发布深度解析

面试官:你了解灰度发布吗?

:灰度发布是一种渐进式的发布策略,将新版本逐步推送给少量用户,验证功能和稳定性后再全量发布,降低发布风险。

面试官:蓝绿部署和金丝雀发布有什么区别?


Q1:蓝绿部署(Blue-Green Deployment)是什么?高频

Section titled “Q1:蓝绿部署(Blue-Green Deployment)是什么?”

原理:同时维护两套完全相同的生产环境(蓝色 = 当前版本,绿色 = 新版本)。

当前状态:
用户 → 负载均衡 → [蓝色环境 v1.0(全量流量)]
[绿色环境 v2.0(空跑,无流量)]
发布步骤:
1. 在绿色环境部署并测试 v2.0
2. 切换负载均衡:将流量全量切到绿色环境
3. 蓝色环境保留(回滚备用)
回滚:
发现问题 → 一键切回蓝色环境(秒级回滚)

优点:切换瞬间完成,回滚简单 缺点:需要双倍资源;新版本问题会影响全量用户


Q2:金丝雀发布(Canary Release)是什么?和蓝绿部署的区别?必考

Section titled “Q2:金丝雀发布(Canary Release)是什么?和蓝绿部署的区别?”

名字由来:矿工用金丝雀探测矿井中的毒气,金丝雀先进入,有问题先撤。

原理:将少量流量(如 5%)引导到新版本,逐渐增加比例,直到全量切换。

阶段一(5% 流量到新版本):
用户 → 网关 → [v1.0 实例 × 19](95% 流量)
[v2.0 实例 × 1] (5% 流量)
阶段二(20%)→ 阶段三(50%)→ 阶段四(100%)
监控每个阶段的错误率、响应时间、业务指标
发现问题 → 立即将金丝雀流量缩减为 0(回滚)

蓝绿 vs 金丝雀

维度蓝绿部署金丝雀发布
资源需求双倍少量即可
风险范围全量(切换瞬间)逐步扩大
回滚速度瞬间(切回)缩减流量比例
验证方式切前测试真实用户小流量验证
适用场景快速全量发布重要功能谨慎发布

Q3:A/B 测试和金丝雀发布的区别?

Section titled “Q3:A/B 测试和金丝雀发布的区别?”
维度A/B 测试金丝雀发布
目的验证哪个方案效果更好(业务决策)验证新版本是否稳定(技术发布)
用户分流按用户特征(地区/年龄/行为)按比例随机
持续时间长(收集统计数据)短(确认稳定后快速全量)
关注指标业务指标(转化率/留存率)技术指标(错误率/延迟)

Q4:如何在 Spring Cloud Gateway 中实现灰度发布?高频

Section titled “Q4:如何在 Spring Cloud Gateway 中实现灰度发布?”

方案一:基于 Header/Cookie 的灰度(定向灰度)

// 自定义灰度路由过滤器
@Component
public class GrayFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
// 根据 Header 判断是否走灰度
String version = request.getHeaders().getFirst("X-Version");
if ("gray".equals(version)) {
// 将请求转发到灰度实例(通过修改服务名或直接指定 IP)
URI grayUri = URI.create("lb://user-service-gray");
ServerHttpRequest newRequest = request.mutate().uri(grayUri).build();
return chain.filter(exchange.mutate().request(newRequest).build());
}
return chain.filter(exchange);
}
}

方案二:基于权重的灰度(随机比例)

spring:
cloud:
gateway:
routes:
- id: user-service-stable
uri: lb://user-service
predicates:
- Path=/api/users/**
- Weight=group1, 90 # 90% 流量
- id: user-service-canary
uri: lb://user-service-canary
predicates:
- Path=/api/users/**
- Weight=group1, 10 # 10% 流量

方案三:结合注册中心的灰度(基于元数据)

# Nacos 实例元数据
nacos:
discovery:
metadata:
version: gray # 或 stable
# 灰度路由规则:将带有 X-Version: gray Header 的请求路由到 version=gray 的实例

Q5:灰度发布中如何保证「粘性会话」(同一用户始终路由到同一版本)?高频

Section titled “Q5:灰度发布中如何保证「粘性会话」(同一用户始终路由到同一版本)?”

问题:用户第一次请求落到新版本,第二次请求落到旧版本,可能出现状态不一致。

解决方案

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String userId = getUserId(exchange);
// 方案一:基于用户 ID 哈希(同一用户永远路由到同一比例)
int hash = Math.abs(userId.hashCode() % 100);
String targetService = hash < grayPercent ? "user-service-gray" : "user-service";
// 方案二:基于 Cookie(第一次分配后写入 Cookie)
HttpCookie versionCookie = exchange.getRequest().getCookies()
.getFirst("X-Service-Version");
String version = versionCookie != null ? versionCookie.getValue() : assignVersion(userId);
// 方案三:基于 Redis 记录用户版本分配
String assignedVersion = redis.get("user:version:" + userId);
if (assignedVersion == null) {
assignedVersion = random.nextInt(100) < grayPercent ? "gray" : "stable";
redis.set("user:version:" + userId, assignedVersion, 7, TimeUnit.DAYS);
}
}