SpringCloud全链路灰度发布

news2024/9/20 20:30:37

日升时奋斗,日落时自省 

目录

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 {
    @Bean
    public 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 {
    @Override
    public 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){
            //获取响应请求头 设置灰度标签的参数 为 true
            response.getHeaders().set(GlobalVariable.GRAY_TAGE,"true");
        }
        // 返回 一个调用链 过滤条件的
        return chain.filter(exchange);
    }
}

5、服务模块

5.1、注册为灰度服务实例

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

spring:
  application:
    name: user-service-gray
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        username: nacos
        password: nacos
        metadata: {"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 {
    //相当于是一个前置操作 处理请求头信息,记录请求日志、实现认证授权
    @Override
    public 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 获得 value
            String value=request.getHeader(key);
            //将获取的参数 放到header头中采用键值 key:value 放到请求模板中
            requestTemplate.header(key,value);
        }
    }
}

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

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

相关文章

【SSM框架】初识Spring

初识Spring Spring家族 Spring发展到今天已经形成了一种开发的生态圈&#xff0c;Spring提供了若千个项目&#xff0c;每个项目用于完成特定的功能 ✅Spring Framework&#xff08;底层框架&#xff09;Spring Boot&#xff08;提高开发速度&#xff09;Spring Cloud&#xf…

【期末不挂科-C++考前速过系列P5】大二C++实验作业-多态性(3道代码题)【解析,注释】

前言 大家好吖&#xff0c;欢迎来到 YY 滴C考前速过系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; YY的《C》专栏YY的《C11》专栏YY的《…

LMDeploy 的量化和部署

LMDeploy 的量化和部署 文档&#xff1a;https://github.com/InternLM/tutorial/blob/vansin-patch-4/lmdeploy/lmdeploy.md 视频&#xff1a;https://www.bilibili.com/video/BV1iW4y1A77P 一、模型量化 大模型参数量很大&#xff0c;运行起来非常消耗显存和内存&#xff0c;…

强化学习应用(八):基于Q-learning的无人机物流路径规划研究(提供Python代码)

一、Q-learning简介 Q-learning是一种强化学习算法&#xff0c;用于解决基于马尔可夫决策过程&#xff08;MDP&#xff09;的问题。它通过学习一个价值函数来指导智能体在环境中做出决策&#xff0c;以最大化累积奖励。 Q-learning算法的核心思想是通过不断更新一个称为Q值的…

漏洞复现-金和OA GetAttOut接口SQL注入漏洞(附漏洞检测脚本)

免责声明 文章中涉及的漏洞均已修复&#xff0c;敏感信息均已做打码处理&#xff0c;文章仅做经验分享用途&#xff0c;切勿当真&#xff0c;未授权的攻击属于非法行为&#xff01;文章中敏感信息均已做多层打马处理。传播、利用本文章所提供的信息而造成的任何直接或者间接的…

使用swift创建第一个ios程序

一、安装xcode 先到app store中下载一个Xcode app 二、创建项目 1、项目设定 创建ios app 2、工程结构 三、修改代码实现按键联动 四、运行测试

Hadoop-HA高可用

一、集群规划 二、HDFS高可用 官方地址 在opt目录下创建一个ha文件夹&#xff0c;将/opt/module/下的 hadoop-3.1.3拷贝到/opt/ha目录下&#xff08;记得删除data 和 log目录&#xff09; 配置core-site.xml hdfs-site.xml <configuration><!-- NameNode数据存…

蓝凌EIS智慧协同平台 多处SQL注入漏洞复现

0x01 产品简介 蓝凌EIS智慧协同平台是一款专为企业提供高效协同办公和团队合作的产品。该平台集成了各种协同工具和功能,旨在提升企业内部沟通、协作和信息共享的效率。 0x02 漏洞概述 由于蓝凌EIS智慧协同平台 doc_fileedit_word.aspx、frm_form_list_main.aspx、frm_butt…

【河海大学论文LaTeX+VSCode全指南】

河海大学论文LaTeXVSCode全指南 前言一、 LaTeX \LaTeX{} LATE​X的安装二、VScode的安装三、VScode的配置四、验证五、优化 前言 LaTeX \LaTeX{} LATE​X在论文写作方面具有传统Word无法比拟的优点&#xff0c;VScode作为一个轻量化的全功能文本编辑器&#xff0c;由于其极强的…

DP读书:《openEuler操作系统》(八)TCP、UDP与跨机器通讯

10min速通TCP与UDP 2024 DP读书计算机网络简介TCP/IP协议栈A. 物理层1.信号及信道传递2.信号调制与调解3.信道的复用 B. 数据链路层1.封装成帧2.透明传输3.差错控制 C. 网络层1.IP2.ARP3.路由选择协议 D. 传输层1.端口号2.3.UDP 2024 DP读书 第八章 跨机器通讯 在第六章之中&a…

Linux配置JAR包为服务实现自启动

一、实现bash脚本 1.1 绘图工具 绘图需安装idea的插件plantUML-Integration 只需要上图一个就可以&#xff0c;别的也不需要装。 启动服务的逻辑如下 关闭服务的逻辑如下 1.2 逻辑实现 在/root路径下创建entrance文件&#xff0c;实现逻辑如下 #!/usr/bin/env bash # 2>…

自动驾驶二维激光雷达标定板

自动驾驶是人类智慧的结晶&#xff0c;它融合了多种高科技技术&#xff0c;包括传感器技术、计算机视觉、人工智能等&#xff0c;它让汽车具备了自主感知和决策的能力&#xff0c;可以在复杂多变的道路环境中自如应对。这种技术带给我们的不仅仅是出行的便利&#xff0c;更是对…

Open3D 反算点云缩放系数(21)

Open3D 反算点云缩放系数(21) 一、算法介绍二、算法实现1.方法12.方法2(通用)一、算法介绍 上一章按照指定的系数,对点云进行了等比例缩放,这里输入缩放后的两块点云,反算二者之间的缩放系数。 二、算法实现 已知使用的俩点云是1/2的缩放关系,用于验证计算结果是否…

JQuery 操作Class滚动轮播展示效果

JQuery 操作Class滚动轮播展示效果 展示效果&#xff1a; 1.html <div class"list"><div class"item"><div class"icon"></div><div class"content">第一行xxxxxxxxx</div></div><div …

NetDevOps:华三交换机通过Netmiko或者Nornir获取接口信息通过TextFSM解析报错问题

python代码&#xff1a;实现功能获取交换机接口信息并通过TextFSM进行解析。 from netmiko import Netmiko import textfsm show_intf_cmd_mapping {hp_comware: display interface, }def ssh_device_2_get_intfs(device_type, host, username, password, port):dev_info {d…

java中多线程

文章目录 多线程进程和线程进程线程 继承Thread类方式实现多线程设置线程名字的两个方式获取正在运行的线程线程调度模型和线程优先级设置两种调度模型优先级设置 线程控制sleepjoin守护线程 线程生命周期 多线程 进程和线程 进程 进程&#xff1a;是正在运行的程序 是系统进…

【非监督学习 02】高斯混合模型

高斯混合模型&#xff08;Guassian Mixed Model, GMM&#xff09;也是一种常见的聚类算法&#xff0c;与K均值算法类似&#xff0c;同样使用了EM算法进行迭代计算。高斯混合模型假设每个簇的数据都是符合高斯分布的&#xff0c;当前数据呈现的分布就是各个簇的高斯分布叠加在一…

手写Webpack-Plugin

Plugin原理 一、Plugin作用 通过插件我们可以扩展webpack&#xff0c;使webpack可以执行更广泛的任务&#xff0c;拥有更强的构建能力。 Plugin工作原理 webpack 就像一条生产线&#xff0c;要经过一系列处理流程后才能将源文件转换成输出结果。 这条生产线上的每个处理流程…

亚马逊时尚如何运用人工智能帮助您找到合适的尺码

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

React16源码: React中的schedule调度整体流程

schedule调度的整体流程 React Fiber Scheduler 是 react16 最核心的一部分&#xff0c;这块在 react-reconciler 这个包中这个包的核心是 fiber reconciler&#xff0c;也即是 fiber 结构fiber 的结构帮助我们把react整个树的应用&#xff0c;更新的流程&#xff0c;能够拆成…