SpringCloud全链路灰度发布

日升时奋斗,日落时自省 

目录

1、实现框架

2、负载均衡模块

3、封装负载均衡器

4、网关模块

5、服务模块

5.1、注册为灰度服务实例

5.2、设置负载均衡器

5.3、传递灰度标签


1、实现框架

Spring Cloud全链路灰色发布实现构架:

灰度发布的具体实现 :

前端程序在灰度测试用户Header头中打上标签,例如Header中添加一个参数"gray-tay:true",其表示要进行会灰度测试的(访问灰度服务),而其他则为正式服务

在负载均衡器Spring Cloud LoadBalancer中,拿到Header中的"gray-tag"进行判断,如果此标签不为空,并等于"true"的话,表示要访问灰度发布的服务,否则只访问正式的服务

在网关Spring Cloud Gateway中,Header标签"gray-tag:true"继续往下一服务中传传递(因为通过网关的时候,是从新发送请求,Header中是没有灰度标签的)

在后续的调用服务中,需要实现以下两个关键功能:

  • 在负载均衡器Spring Cloud LoadBalancer中,判断灰度发布标签,将请求分发到对应服务
  • 将灰度发布标签(如果存在),继续传递给下一个调用的服务

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

2、负载均衡模块

实现ReactorServiceInstanceLoadBalancer接口

public class GrayLoadBalancer implements ReactorServiceInstanceLoadBalancer{private static final Log log = LogFactory.getLog(GrayLoadBalancer.class);private final String serviceId;private AtomicInteger position; // 位置,下标private ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;public GrayLoadBalancer(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider, String serviceId) {this.serviceId = serviceId;this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;this.position = new AtomicInteger(new Random().nextInt(1000));  //随机进行设置一个值}public Mono<Response<ServiceInstance>> choose(Request request) {// 提供备选的服务实例列表ServiceInstanceListSupplier supplier = (ServiceInstanceListSupplier) this.serviceInstanceListSupplierProvider.getIfAvailable(NoopServiceInstanceListSupplier::new);// 选择服务实例return supplier.get(request).next().map((serviceInstances) -> {return this.processInstanceResponse(supplier, serviceInstances, request);});}private Response<ServiceInstance> processInstanceResponse(ServiceInstanceListSupplier supplier,List<ServiceInstance> serviceInstances,Request request) {// 从备选的服务列表中选择一个具体的服务实例Response<ServiceInstance> serviceInstanceResponse = this.getInstanceResponse(serviceInstances,request);if (supplier instanceof SelectedInstanceCallback && serviceInstanceResponse.hasServer()) {((SelectedInstanceCallback) supplier).selectedServiceInstance((ServiceInstance) serviceInstanceResponse.getServer());}return serviceInstanceResponse;}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 { // 服务不为空// 灰度节点的业务实现// 0.得到 Request 对象[通过方法参数的传递得到此对象]// 1.从 Request 对象的 Header 中得到灰度标签RequestDataContext requestContext = (RequestDataContext) request.getContext();HttpHeaders headers = requestContext.getClientRequest().getHeaders();List<String> headersList = headers.get(GlobalVariable.GRAY_TAGE);if (headersList != null && headersList.size() > 0 &&headersList.get(0).equals("true")) { // 灰度请求// 灰度列表  这里采用lambda的方法进行过滤List<ServiceInstance> grayList = instances.stream().filter(i -> i.getMetadata().get(GlobalVariable.GRAY_TAGE) != null &&i.getMetadata().get(GlobalVariable.GRAY_TAGE).equals("true")).toList();if (grayList.size() > 0) { // 存在灰度服务节点instances = grayList;}} else { // 正式节点// 2.将实例进行分组【正式服务列表|灰度服务列表】instances = instances.stream().filter(i -> i.getMetadata().get(GlobalVariable.GRAY_TAGE) == null ||!i.getMetadata().get(GlobalVariable.GRAY_TAGE).equals("true")).toList();}// 3.使用负载均衡算法选择上一步列表中的某一个节点int pos = this.position.incrementAndGet() & Integer.MAX_VALUE;ServiceInstance instance = (ServiceInstance)instances.get(pos % instances.size());return new DefaultResponse(instance);}}
}

3、封装负载均衡器

负载均衡器修改之后,我们需要使用修改后的负载均衡器

public class GrayLoadBalancerConfig {@Beanpublic ReactorLoadBalancer<ServiceInstance> GrayLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) {String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);return new GrayLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);}
}

4、网关模块

网关是能收到灰度发布标识,但是调用的服务是不能获得Header中的灰度标签,需要在网关这里传递给调用的服务

@Component // 实现全局过滤器 进行过滤设置
public class LoadBalancerFilter implements GlobalFilter {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {// 事件处理 exchange 获取请求头ServerHttpRequest request=exchange.getRequest();// 事件处理 exchange 获取响应头ServerHttpResponse response = exchange.getResponse();// 请求头参数 获取的参数 获取 key 对应的 value值if(request.getQueryParams().getFirst(GlobalVariable.GRAY_TAGE)!=null){//获取响应请求头 设置灰度标签的参数 为 trueresponse.getHeaders().set(GlobalVariable.GRAY_TAGE,"true");}// 返回 一个调用链 过滤条件的return chain.filter(exchange);}
}

5、服务模块

5.1、注册为灰度服务实例

在负载均衡器上获得了metaData数据,这个数据就是从灰色服务实例中获取,数据存储在nacos中

spring:application:name: user-service-graycloud:nacos:discovery:server-addr: localhost:8848username: nacospassword: nacosmetadata: {"gray-tag":"true"}  #metadata可以自定义一些元数据
server:port: 0

5.2、设置负载均衡器

在服务启动类设置负载均衡器和开启OpenFeign服务:

defaultConfiguration = GrayLoadBalancerConfig.class全局负载均衡器的配置

@SpringBootApplication
@EnableFeignClients  //启用Fegin客户端使用
//这里需要调用我们写的负载均衡器,我们自定义的负载均衡器主要就是为了检测gray参数
@LoadBalancerClients(defaultConfiguration = GrayLoadBalancerConfig.class)  
public class NewUserServiceApplication {public static void main(String[] args) {SpringApplication.run(NewUserServiceApplication.class, args);}}

5.3、传递灰度标签

针对其他服务实例需要处理请求头信息

RequestInterceptor是一个Spring Cloud Feign中的接口,它用于在发起Feign请求前和请求后执行一些自定义的操作,例如添加请求头信息、记录请求日志、实现认证授权等

RequestInterceptor接口中包含一个方法:

apply方法:在发送请求之前执行的操作,比如添加请求头、修改请求路径或请求参数等

@Component
public class FeignRequestInterceptor implements RequestInterceptor {//相当于是一个前置操作 处理请求头信息,记录请求日志、实现认证授权@Overridepublic void apply(RequestTemplate requestTemplate) {//获取请求参数ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();//拿到请求  HttpServletRequest request = attributes.getRequest();//获取请求头参数  当然调用上面这条代码的 request是一样的Enumeration<String> headerNames = attributes.getRequest().getHeaderNames();//将获取的请求中的所有参数while(headerNames.hasMoreElements()){//将key先获取String key=headerNames.nextElement();//通过key 获得 valueString value=request.getHeader(key);//将获取的参数 放到header头中采用键值 key:value 放到请求模板中requestTemplate.header(key,value);}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/620703.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GEE机器学习——利用最短距离方法进行土地分类和精度评定

最短距离方法 最短距离方法(Minimum Distance)是一种常用的模式识别算法,用于计算样本之间的相似度或距离。该方法通过计算样本之间的欧氏距离或其他距离度量,来确定样本之间的相似程度或差异程度。 最短距离方法的具体步骤如下: 1. 数据准备:收集并准备用于训练的数据…

golang学习-函数

1、匿名函数 没有函数名的函数&#xff0c;格式如下&#xff1a; func(参数)返回值{ 函数体 } func main() {//将匿名函数保存到变量中sum : func(x, y int) int {return x y}fmt.Println(sum(10, 20)) //通过变量调用匿名函数//自执行函数:匿名函数定义完加()直接执行fu…

Java中的继承、方法覆盖和多态

一、继承 关于java语言当中的继承&#xff1a; 1.继承是面向对象三大特征之一&#xff0c;三大特征分别是&#xff1a;封装、继承、多态 2.继承最”基本“的作用是&#xff1a;代码复用。但是继承最”重要“的作用是&#xff1a;有了 继承才有了以后”方法的覆盖“和”多态机制…

利用Monte Carlo进行数值积分(二)

进步空间很大的算法版本 话说去年6月的一个周六&#xff0c;我很无聊地发了一个帖子&#xff0c;写了一个自己感觉有点无聊的帖子。 Matlab多重积分的两种实现【从六重积分到一百重积分】https://withstand.blog.csdn.net/article/details/127564478 这个帖子居然成了我这种懒…

springboot整合 hibernate详解

springboot整合 hibernate详解 大家好&#xff0c;我是免费搭建查券返利机器人赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天&#xff0c;我们将深入研究Spring Boot与Hibernate整合的技术&#xff0c;解析其…

实现数字的千分位,表示,

重点如下 区分是否是负数区分是否有小数点使用正则表达式\B 是指非单词边界? 是正向查找?! 是负向查找 代表有一个或者多个() 是分组g 代表全局匹配 function splitStr(num) {// 转化成字符串let numStr ${num}let isNegative falseif (numStr.startsWith(-)) {isNegativ…

求解建公路问题

课程设计题目 求解建公路问题 课程设计目的 深入掌握 Prim 和 Kruskal算法在求解实际问题中的应用 问题描述 假设有 n 个村庄,编号从到,现在修建一些道路使任意两个村庄之间可以互相连通。所谓两个村庄 A 和B是连通的,指当且仅当A 和 B之间有一条道路或者存在一个村庄 C 使得…

QT通过QPdfWriter类实现pdf文件生成与输出

一.QPdfWriter类介绍 本文代码工程下载地址&#xff1a; https://download.csdn.net/download/xieliru/88736664?spm1001.2014.3001.5503 QPdfWrite是一个用于创建PDF文件的类&#xff0c;它是Qt库的一部分。它提供了一些方法和功能&#xff0c;使您能够创建和写入PDF文件。…

#Prompt##提示词工程##AIGC##LLM#使用大型预训练语言模型的关键考量

如果有不清楚的地方可以评论区留言&#xff0c;我会给大家补上的&#xff01; 本文包括&#xff1a; Prompt 的一些行业术语介绍 Prompt 写好提示词的方法经验介绍&#xff08;附示例教程&#xff09; LLM自身存在的问题&#xff08;可以用Prompt解决的以及无法用Prompt解决的&…

u盘监控系统—公司电脑如何监控U盘使用?【详解】

在当今的办公环境中&#xff0c;U盘等移动存储设备已成为数据传输和存储的重要工具。 然而&#xff0c;随着U盘的广泛使用&#xff0c;也带来了潜在的安全风险&#xff0c;如数据泄露、病毒传播等。 因此&#xff0c;对于随时会有数据泄露风险的企业而言&#xff0c;U盘的使用…

动态规划篇-00:解题思想与框架

引言 这篇文章是我的第一个专栏的第一篇文章。 在这篇文章中&#xff0c;我将总结我对于动态规划的认识与解题框架。这些思想和框架将会在后面的习题中反复出现。 解题思想 对于所有的算法题来说&#xff0c;本质上都是“穷举”——列出所有的结果&#xff0c;然后选择最优…

数组中差值的最大值(寻找一个数组中左侧最大值与右侧最小值的差值)

今天跟大伙分享下关于数组中差值的最大值&#xff08;寻找一个数组中左侧最大值与右侧最小值的差值&#xff09;的计算思路的算法题&#xff0c;解决方案有许多&#xff0c;这里简单进行抛砖引玉。 题目一&#xff1a; 数组中差值的最大值&#xff08;寻找一个数组中左侧最大值…

javascript编程求三个数中最大的数

使用javascript编程求输入的三个数中最大数&#xff0c;并在页面打印出来 <!DOCTYPE html> <html> <head><meta charset"utf-8"><meta name"viewport" content"widthdevice-width, initial-scale1"><title>…

DrissionPage获取浏览器Network数据包

DrissionPage是什么&#xff1f; GitHub - g1879/DrissionPage: 基于python的网页自动化工具。既能控制浏览器&#xff0c;也能收发数据包。可兼顾浏览器自动化的便利性和requests的高效率。功能强大&#xff0c;内置无数人性化设计和便捷功能。语法简洁而优雅&#xff0c;代码…

深度学习基本介绍-李沐

目录 AI分类&#xff1a;模型分类&#xff1a;广告案例&#xff1a; bilibili视频链接&#xff1a;https://www.bilibili.com/video/BV1J54y187f9/?p2&spm_id_frompageDriver&vd_sourcee6a6e7fec41c59c846c142eb5ef1da0b AI分类&#xff1a; 模型分类&#xff1a; 图…

【每日一题】删除排序链表中的重复元素

文章目录 Tag题目来源解题思路方法一&#xff1a;比较相邻两节点 写在最后 Tag 【遍历】【链表】【2024-01-14】 题目来源 83. 删除排序链表中的重复元素 解题思路 方法一&#xff1a;比较相邻两节点 思路 比较两个相邻的节点&#xff0c;如果下一个节点值和当前节点值一样…

简单高效 LaTeX 科学排版 第004集 命令与环境

这是《简单高效LaTeX》的第四个视频&#xff0c;主要演示讨论基本命令与排版环境&#xff0c;还有保留字符。 视频地址&#xff1a;https://www.ixigua.com/7298100920137548288?id7298102807985390120&logTagf853f23a668f8a2ee405

IPv6组播技术--MLDv2

MPLDv1工作机制 IPv6组播网络中RouterA和RouterB连接主机网段,在主机网段上有HostA、HostB、HostC三个接收者。假设HostA和HostB想要接收发往组播组G1的数据,HostC想要接收发往组播组G2的数据。 查询器选举机制 当一个网段内有多台IPv6组播路由器时,由于它们都可以接收到…

初识XSS漏洞

目录 一、XSS的原理和分类 二、Xss漏洞分类 1. 反射性xss 简单的演示&#xff1a; 2.基于DOM的XSS 简单的演示&#xff1a; 3.存储型XSS ​编辑简单的演示 4、self xss 三、XSS漏洞的危害 四、XSS漏洞的验证 五、XSS漏洞的黑盒测试 六、XSS漏洞的白盒测试 七、XS…

html+JavaScript的媒体元素

<video src"conference.mpg" id"myVideo">Video player not available.</video> <!-- 嵌入音频 --> <audio src"song.mp3" id"myAudio">Audio player not available.</audio> - 属性 每个元素至少…