如何设计一个灰度发布系统
这个主要围绕全链路的一致性,动态调整,出了事故快速回滚。
(1)分流策略,很多人首选按IP分流,这个方案最坑,IP是会变的。
同一个用户手机和电脑IP不同,家里和公司IP不同,来回跳板是必然的。
正确做法是,按用户IP做一致性哈希分流,同一个用户,永远路由到同一个版本,从根源上解决体验不一致的问题。
一致性哈希在网关层怎么实现?
在Spring Cloud GateWay里写一个自定义的过滤器,从请求头或Token里,解析用户ID,对灰度比例取模,命中范围的路由到新版本实例,灰度比例存在配置中心,改配置实时生效,不需要重启网关,从5%开始,观察10分钟没问题,再调到20%,再到50%,最后全量放开;
(2)流量染色,这个灰度发布,最容易忽略的关键,光网关分流不够,得保证灰度用户的请求,在整条的调用链上都走新版本,网关识别到灰度用户后,在请求头里,打一个灰度的标记,比如X-gray-tag,这个标记通过拦截器,透传到下游的所有的服务,下游服务看到标记,就可以走新版本的逻辑,异步场景的染色绝对不能漏,如果灰度请求触发MQ消息,必须在消息里也带上灰度标记,消费者根据标记走不同的逻辑;
(3)回滚机制,最稳定的回滚方案机制是保留旧版本实例不动,新版本独立部署,出了问题,直接在配置中心,把灰度比例调成0,所有流量瞬间回归到旧版本,不需要重新部署,还有一点,数据库变更,必须向前兼容,新版本加的字段,旧版本可以忽略,但绝对不能改字段类型,或者删除字段,否则旧版本就读不了新数据,回滚都没用。
AI回答:
我帮你把这段整理成“大厂面试可讲、技术准确、能被追问”的版本。先记住核心主线:
全链路灰度 = 稳定身份分流 + 全链路染色 + 异步透传 + 数据/消息兼容 + 动态调比例 + 秒级回滚。
不是只做网关分流,也不是只改配置比例。灰度发布的核心是:同一用户始终命中同一版本,灰度流量在整条链路走新逻辑,出事故能快速回滚且数据不崩。
一、先纠偏:原答案里的主要问题
-
“按用户IP做一致性哈希分流”自相矛盾
前面说 IP 会变、按 IP 分流最坑,后面又写按用户 IP 做一致性哈希。正确应是按 用户 ID / 账号 ID / 设备 ID / 租户 ID 这种稳定身份做哈希分桶。 -
“对灰度比例取模”不准确
正确是:hash(userId) % 100 < grayPercent,或按万分比:hash(userId) % 10000 < grayPercent * 100。不是对灰度比例取模。 -
严格说,灰度分流常用“哈希分桶”,不是一致性哈希环
一致性哈希主要用于后端节点扩缩容时减少重映射。灰度比例动态调整时,更常用用户 ID 哈希分桶。面试时可以说“按稳定用户 ID 做哈希分桶,保证同一用户稳定命中”。 -
只讲网关分流不够
还要讲 HTTP/RPC/MQ/线程池/定时任务/缓存等全链路染色透传。 -
回滚不只是流量切回
数据库、消息格式、缓存、状态机都要兼容,否则流量回旧版本,旧代码读不了新数据,事故会扩大。 -
灰度比例动态调整要配监控和自动回滚
不是 5% → 20% → 50% 拍脑袋放量,要看错误率、P99、业务指标、日志、Trace、告警。
二、整改后 2 分钟面试逐字稿
这个项目我主要负责全链路灰度发布,核心目标是三件事:全链路一致性、动态调整、事故快速回滚。
第一,分流策略。我们不按 IP 分流,因为 IP 不稳定,同一用户手机和电脑不同、家里和公司不同、NAT 和基站切换都会变。我们按稳定身份分流,比如 userId、accountId、deviceId。算法是
hash(userId) % 100 < grayPercent,命中就走新版本。这样同一用户永远命中同一版本,体验一致。在 Spring Cloud Gateway 里,我们写自定义 GlobalFilter,从 JWT 或请求头解析 userId,读取配置中心的灰度比例,计算是否灰度,然后给请求打上
X-Gray-Tag,通过 LoadBalancer 或路由规则转发到新版本实例组。灰度比例存在配置中心,改完实时生效,不用重启网关。放量节奏是 5% 观察 10 分钟,没问题再到 20%、50%,最后全量。第二,流量染色。光网关分流不够,必须保证灰度请求在整条调用链都走新版本。网关识别灰度用户后,在请求头打
X-Gray-Tag,下游通过 Filter、Interceptor、Feign、RestTemplate、RPC 拦截器透传。异步场景尤其不能漏:如果灰度请求发 MQ 消息,必须在消息 header 里带灰度标记,消费者根据标记走新逻辑。线程池、定时任务、补偿任务也要处理上下文透传。还要注意安全,外部传入的 gray tag 不可信,网关要覆盖或清除,防止用户伪造标记绕过灰度。第三,回滚机制。最稳的是新旧版本独立部署,旧版本实例保留。出问题直接在配置中心把灰度比例调成 0,所有流量瞬间回旧版本,不用重新部署。但回滚能不能成功,关键看数据兼容。数据库变更必须双向兼容:新版本只加字段,旧版本可以忽略;绝对不能改字段类型、删字段、重命名字段,否则旧代码读不了新数据,回滚也没用。MQ 消息也要兼容,新格式旧消费者能忽略或兼容,必要时双版本消费。
最后,动态调整要配合监控:错误率、P99、业务指标、Trace、日志、MQ 积压。异常可以自动或手动把灰度比例归零。核心就是:稳定身份分流、全链路染色、异步透传、数据兼容、配置动态生效、回滚预案可执行。
三、关键点拆解
1. 分流策略:按稳定身份,不按 IP
为什么不用 IP?
- 手机和电脑 IP 不同;
- 家里和公司 IP 不同;
- 移动网络、NAT、代理、基站切换都会变;
- 同一用户可能被分到不同版本,体验不一致。
正确做法:
- 已登录:userId / accountId;
- 未登录:deviceId / 临时 cookie / 租户 ID;
- 算法:
hash(stableId) % 100 < grayPercent; - 比例扩大时,建议按固定桶扩大,比如 0-4 先灰度,扩到 20 时 0-19 灰度,保证已灰度用户不跳回旧版本。
网关实现:
- Spring Cloud Gateway 自定义 GlobalFilter;
- 从 JWT / Header 解析 userId;
- 读配置中心灰度比例;
- 计算是否灰度;
- 打
X-Gray-Tag; - 路由到新版本实例组;
- 配置中心动态推送,无需重启。
2. 流量染色:全链路透传
要透传的链路:
- HTTP:Header;
- RPC:隐式参数 / Attachment;
- MQ:消息 Header;
- 线程池:TransmittableThreadLocal / 上下文包装;
- 定时任务:默认走旧版本或按开关;
- 缓存:key 可带版本或灰度标识,避免脏读。
异步场景:
- 灰度请求发 MQ,消息 header 带
X-Gray-Tag; - 消费者根据 tag 走新逻辑;
- 旧消费者收到新消息要能忽略 tag,保证兼容。
安全:
- 外部请求不可信;
- 网关要覆盖或清除外部传入的 gray tag;
- 只信任内部签发的染色标记。
3. 回滚机制:流量回滚 + 数据兼容
流量回滚:
- 新旧版本独立部署;
- 旧版本保留;
- 配置中心灰度比例调 0;
- 流量秒回旧版本;
- 不需要重新部署。
数据兼容:
- 只加字段,不改类型,不删字段,不重命名;
- 旧代码能忽略新字段;
- 新代码兼容旧数据;
- 回滚后新版本已写入的数据要能处理;
- 必要时做数据修复、对账、补偿。
消息兼容:
- 新消息格式旧消费者能兼容;
- 或双版本消费;
- 避免回滚后旧消费者解析新消息失败。
4. 动态调整与监控
放量节奏:
- 5% → 观察 10 分钟 → 20% → 50% → 100%;
- 每阶段看错误率、P99、业务指标、日志、Trace、MQ 积压。
自动回滚:
- 错误率超阈值;
- P99 飙升;
- 核心业务指标下跌;
- 自动或手动把灰度比例归零。
四、面试官可能追问
Q1:为什么不用 IP 做灰度?
IP 不稳定,同一用户多设备、多网络会变,导致同一用户在不同版本间跳,体验不一致。要用 userId、accountId、deviceId 等稳定身份。
Q2:一致性哈希和哈希取模有什么区别?
一致性哈希主要用于节点扩缩容时减少重映射;灰度分流更常用用户 ID 哈希分桶,比如
hash(userId) % 100 < grayPercent。关键是保证同一用户稳定命中。
Q3:未登录用户怎么分流?
用 deviceId、临时 cookie、租户 ID 等稳定标识;实在没有,才用 IP 兜底,但要接受体验可能不一致。
Q4:MQ 异步链路怎么染色?
生产者在消息 header 带
X-Gray-Tag,消费者读取 tag 走对应逻辑。旧消费者要能忽略 tag,保证兼容。
Q5:数据库怎么做到可回滚?
双向兼容:新代码兼容旧数据,旧代码兼容新数据。只加字段,不改类型,不删字段,不重命名。回滚后旧代码能正常读新数据。
Q6:回滚后新版本写入的数据怎么办?
提前设计兼容逻辑;必要时数据修复、对账、补偿。核心是旧版本能识别或忽略新数据,不能直接崩。
Q7:怎么防止用户伪造灰度标记?
网关清除外部传入的 gray tag,只信任内部签发的标记。外部请求不能直接决定自己是否灰度。
Q8:怎么验证全链路一致性?
构造灰度用户,检查所有服务日志和 Trace 都带同一个 gray tag;MQ 消费者版本正确;数据库和缓存读写版本一致。
五、收尾话术
所以全链路灰度不是简单按比例分流,而是:按稳定身份做哈希分桶,网关打标,全链路透传,异步 MQ 染色,数据双向兼容,配置中心动态调比例,出事故比例归零快速回滚。核心目标是同一用户版本一致、整条链路逻辑一致、回滚时数据和消息不崩。

浙公网安备 33010602011771号