灰度发布(Gray Release,也称为灰度发布或金丝雀发布)是指在软件或服务发布过程中,将新版本的功能或服务以较小的比例引入到生产环境中,仅向部分用户或节点提供新功能的一种发布策略。

在传统的全量发布中,新版本的功能会一次性全部部署到所有的用户或节点上。然而,这种方式潜在的风险是,如果新版本存在缺陷或问题,可能会对所有用户或节点产生严重的影响,导致系统崩溃或服务不可用。

相比之下,灰度发布采用较小的规模,并逐步将新版本的功能引入到生产环境中,仅向一小部分用户或节点提供新功能。通过持续监测和评估,可以在发现问题时及时回滚或修复。这种逐步引入新版本的方式可以降低风险,并提高系统的稳定性和可靠性。

1.实现思路

灰色发布的常见实现思路有以下几种:

  • 根据用户划分:根据用户标识或用户组进行划分,在整个用户群体中只选择一小部分用户获得新功能。
  • 根据地域划分:在不同地区或不同节点上进行划分,在其中的一小部分地区或节点进行新功能的发布。
  • 根据流量划分:根据流量的百分比或请求次数进行划分,只将一部分请求流量引导到新功能上。

而在生产环境中,比较常用的是根据用户标识来实现灰色发布,也就是说先让一小部分用户体验新功能,以发现新服务中可能存在的某种缺陷或不足。

2.具体实现

Spring Cloud 全链路灰色发布的关键实现思路如下图所示:



灰度发布的具体实现步骤如下:

  1. 前端程序在灰度测试的用户 Header 头中打上标签,例如在 Header 中添加“grap-tag: true”,其表示要进行灰常测试(访问灰度服务),而其他则为访问正式服务。
  2. 在负载均衡器 Spring Cloud LoadBalancer 中,拿到 Header 中的“grap-tag”进行判断,如果此标签不为空,并等于“true”的话,表示要访问灰度发布的服务,否则只访问正式的服务。
  3. 在网关 Spring Cloud Gateway 中,将 Header 标签“grap-tag: true”继续往下一个调用服务中传递。
  4. 在后续的调用服务中,需要实现以下两个关键功能:
    1. 在负载均衡器 Spring Cloud LoadBalancer 中,判断灰度发布标签,将请求分发到对应服务。
    2. 将灰度发布标签(如果存在),继续传递给下一个调用的服务。

经过第四步的反复传递之后,整个 Spring Cloud 全链路的灰度发布就完成了。

3.核心实现思路和代码

灰度发布的关键实现技术和代码如下。

3.1 区分正式服务和灰度服务

在灰度发布的执行流程中,有一个核心的问题,如果在 Spring Cloud LoadBalancer 进行服务调用时,区分正式服务和灰度服务呢?

这个问题的解决方案是:在灰度服务既注册中心的 MetaData(元数据)中标识自己为灰度服务即可,而元数据中没有标识(灰度服务)的则为正式服务,以 Nacos 为例,它的设置如下:

spring:
application:
name: canary-user-service
cloud:
nacos:
discovery:
username: nacos
password: nacos
server-addr: localhost:8848
namespace: public
register-enabled: true
metadata: { "grap-tag":"true" } # 标识自己为灰度服务

3.2 负载均衡调用灰度服务

Spring Cloud LoadBalancer 判断并调用灰度服务的关键实现代码如下:

private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances,
Request request) {
// 实例为空
if (instances.isEmpty()) {
if (log.isWarnEnabled()) {
log.warn("No servers available for service: " + this.serviceId);
}
return new EmptyResponse();
} else { // 服务不为空
RequestDataContext dataContext = (RequestDataContext) request.getContext();
HttpHeaders headers = dataContext.getClientRequest().getHeaders();
// 判断是否为灰度发布(请求)
if (headers.get(GlobalVariables.GRAY_KEY) != null &&
headers.get(GlobalVariables.GRAY_KEY).get(0).equals("true")) {
// 灰度发布请求,得到新服务实例列表
List<ServiceInstance> findInstances = instances.stream().
filter(s -> s.getMetadata().get(GlobalVariables.GRAY_KEY) != null &&
s.getMetadata().get(GlobalVariables.GRAY_KEY).equals("true"))
.toList();
if (findInstances.size() > 0) { // 存在灰度发布节点
instances = findInstances;
}
} else { // 查询非灰度发布节点
// 灰度发布测试请求,得到新服务实例列表
instances = instances.stream().
filter(s -> s.getMetadata().get(GlobalVariables.GRAY_KEY) == null ||
!s.getMetadata().get(GlobalVariables.GRAY_KEY).equals("true"))
.toList();
}
// 随机正数值 ++i( & 去负数)
int pos = this.position.incrementAndGet() & Integer.MAX_VALUE;
// ++i 数值 % 实例数 取模 -> 轮询算法
int index = pos % instances.size();
// 得到服务实例方法
ServiceInstance instance = (ServiceInstance) instances.get(index);
return new DefaultResponse(instance);
}
}

以上代码为自定义负载均衡器,并使用了轮询算法。如果 Header 中有灰度标签,则只查询灰度服务的节点实例,否则则查询出所有的正式节点实例(以供服务调用或服务转发)。

3.3 网关传递灰度标识

要在网关 Spring Cloud Gateway 中传递灰度标识,只需要在 Gateway 的全局自定义过滤器中设置 Response 的 Header 即可,具体实现代码如下:

package com.example.gateway.config;

import com.loadbalancer.canary.common.GlobalVariables;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono; @Component
public class LoadBalancerFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 得到 request、response 对象
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
if (request.getQueryParams().getFirst(GlobalVariables.GRAY_KEY) != null) {
// 设置金丝雀标识
response.getHeaders().set(GlobalVariables.GRAY_KEY,
"true");
}
// 此步骤正常,执行下一步
return chain.filter(exchange);
}
}

3.4 Openfeign 传递灰度标签

HTTP 调用工具 Openfeign 传递灰度标签的实现代码如下:

import feign.RequestInterceptor;
import feign.RequestTemplate;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes; import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.Map; @Component
public class FeignRequestInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate template) {
// 从 RequestContextHolder 中获取 HttpServletRequest
ServletRequestAttributes attributes = (ServletRequestAttributes)
RequestContextHolder.getRequestAttributes();
// 获取 RequestContextHolder 中的信息
Map<String, String> headers = getHeaders(attributes.getRequest());
// 放入 openfeign 的 RequestTemplate 中
for (Map.Entry<String, String> entry : headers.entrySet()) {
template.header(entry.getKey(), entry.getValue());
}
} /**
* 获取原请求头
*/
private Map<String, String> getHeaders(HttpServletRequest request) {
Map<String, String> map = new LinkedHashMap<>();
Enumeration<String> enumeration = request.getHeaderNames();
if (enumeration != null) {
while (enumeration.hasMoreElements()) {
String key = enumeration.nextElement();
String value = request.getHeader(key);
map.put(key, value);
}
}
return map;
}
}

小结

灰度发布是微服务时代保证生产环境安全的必备措施,而其关键实现思路是:

1、注册中心区分正常服务和灰度服务;

2、负载均衡正确转发正常服务和灰度服务;

3、网关和 HTTP 工具传递灰度标签。

这样,我们就完整的实现 Spring Cloud 全链路灰度发布功能了。

本文已收录到我的面试小站 www.javacn.site,其中包含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、消息队列等模块。

SpringCloud全链路灰色发布具体实现!的更多相关文章

  1. 基于 Istio 的全链路灰度方案探索和实践

    作者|曾宇星(宇曾) 审核&校对:曾宇星(宇曾) 编辑&排版:雯燕 背景 微服务软件架构下,业务新功能上线前搭建完整的一套测试系统进行验证是相当费人费时的事,随着所拆分出微服务数量的不 ...

  2. 持续引领大数据行业发展,腾讯云发布全链路数据开发平台WeData

    9月11日,在腾讯全球数字生态大会大数据专场上,腾讯云大数据产品副总经理雷小平重磅发布了全链路数据开发平台WeData,同时发布和升级了流计算服务.云数据仓库.ES.企业画像等6款核心产品,进一步优化 ...

  3. ApiTesting全链路自动化测试框架 - 初版发布(一)

    简介 此框架是基于Python+Pytest+Requests+Allure+Yaml+Json实现全链路接口自动化测试. 主要流程:解析接口数据包 ->生成接口基础配置(yml) ->生 ...

  4. Go微服务全链路跟踪详解

    在微服务架构中,调用链是漫长而复杂的,要了解其中的每个环节及其性能,你需要全链路跟踪. 它的原理很简单,你可以在每个请求开始时生成一个唯一的ID,并将其传递到整个调用链. 该ID称为Correlati ...

  5. Opentracing + Uber Jaeger 全链路灰度调用链,Nepxion Discovery

    当网关和服务在实施全链路分布式灰度发布和路由时候,我们需要一款追踪系统来监控网关和服务走的是哪个灰度组,哪个灰度版本,哪个灰度区域,甚至监控从Http Header头部全程传递的灰度规则和路由策略.这 ...

  6. 基于Opentracing+Jaeger全链路灰度调用链

    当网关和服务在实施全链路分布式灰度发布和路由时候,我们需要一款追踪系统来监控网关和服务走的是哪个灰度组,哪个灰度版本,哪个灰度区域,甚至监控从Http Header头部全程传递的灰度规则和路由策略.这 ...

  7. 高德APP全链路源码依赖分析工程

    一.背景 高德 App 经过多年的发展,其代码量已达到数百万行级别,支撑了高德地图复杂的业务功能.但与此同时,随着团队的扩张和业务的复杂化,越来越碎片化的代码以及代码之间复杂的依赖关系带来诸多维护性问 ...

  8. skywalking与pinpoint全链路追踪方案对比

    由于公司目前有200多微服务,微服务之间的调用关系错综复杂,调用关系人工维护基本不可能实现,需要调研一套全链路追踪方案,初步调研之后选取了skywalking和pinpoint进行对比; 选取skyw ...

  9. 全链路监控系统开源Pinpoint入门视频教程(最新版本1.8)

    pinpoint支持的模块 源码:https://github.com/naver/pinpoint技术概述:https://skyao.gitbooks.io/learning-pinpoint/c ...

  10. <转>二十问全链路压测干货汇总(上)

    本文转载自:微信公众号-数列科技<二十问全链路压测干货汇总(上)> 最近几年全链路压测无疑成为了一个热门话题,在各个技术峰会上都可以看到它的身影. 一些大型的互联网公司,比如阿里巴巴.京东 ...

随机推荐

  1. Python和PyTorch深入实现线性回归模型:一篇文章全面掌握基础机器学习技术

    1. 简介 1.1 线性回归模型概述 线性回归是一种统计学中的预测分析,该方法用于建立两种或两种以上变量间的关系模型.线性回归使用最佳的拟合直线(也称为回归线)在独立(输入)变量和因变量(输出)之间建 ...

  2. npm 切换源

    切换到淘宝源 npm config set registry https://registry.npm.taobao.org 切换回官方源 npm config set registry http:/ ...

  3. NativeBuferring,一种零分配的数据类型[下篇]

    上文说到Unmanaged.BufferedBinary和BufferedString是NativeBuffering支持的三个基本数据类型,其实我们也可以说NativeBuffering只支持Unm ...

  4. Xshell使用技巧及常用配置

    Xshell使用 1.调整 Xshell 的终端显示和回滚缓冲区大小 磨刀不误砍柴工,为了更方便地学习 Linux,首先得对终端进行一些调整,步骤如下: 首先通过 xshell 顶部菜单中的文件--& ...

  5. 宝塔linux网站搬家思路

    对于一个网站来说,其实就分为两个部分,一个是网站的源码,另一个就是网站的数据库. 那么对于网站搬家而言,要考虑的也就是两点,一是要打包网站的源码,再者就是要打包网站的数据库.其次就是要在新的站点,配置 ...

  6. 行行AI人才直播第15期:【AIGC科技公司法律顾问】Amber《AIGC的法律挑战》

    近年来,AIGC技术的迅速进步为社会经济发展带来了新的机遇.各行各业都开始关注AIGC相关技术在商业落地中的应用,AIGC相关的创业及项目如雨后春笋般涌现.然而,AIGC的广泛应用也带来了一系列的法律 ...

  7. 独奏者2 序章的wp

    0x01 0ctf_2017_babyheap 2023.7.24 国防科技大学 合肥 本题除了fastbin attack,最重要的是伪造fakechunk,使得存放chunk的指针有两个指向同一个 ...

  8. ios设备管理

    管理设备

  9. BZ全景可视化编辑器 (KRPano可视化编辑器, 无需编写任何代码制作全景漫游)

    软件简介 BZ全景编辑器是一款KRPano全景可视化编辑工具,下载安装即可使用,无需拥有任何KRPano代码基础,便可以制作生成精美的全景漫游作品. 官方网站: 点击进入官方网站 最新版软件下载地址: ...

  10. MySQL-通过存储过程来添加和删除分区(List分区)

    1.背景原因 当前MySQL不支持在添加和删除分区时,使用IF NOT EXISTS和IF EXISTS.所以在执行调度任务时,直接通过ADD PARTITION和DROP PARTITION不可避免 ...