当前位置:   article > 正文

微服务实现全链路灰度发布_全链路灰度发布配置文件

全链路灰度发布配置文件

一、实现步骤

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

二、服务模块

2.1 注册为灰色服务实例

  1. spring:
  2. application:
  3. name: user-service
  4. cloud:
  5. nacos:
  6. discovery:
  7. server-addr: localhost:8848
  8. username: nacos
  9. password: nacos
  10. metadata:
  11. {"gray-tag":true} #标识当前为灰度节点
  12. server:
  13. port: 0

2.2 设置负载均衡器

在服务启动类设置父子均衡器和Openfeign 服务 

  1. @SpringBootApplication
  2. @LoadBalancerClients(defaultConfiguration = GllobalLoadbanlancerConfig.class)
  3. @EnableFeignClients
  4. public class UserServiceGrayApplication {
  5. public static void main(String[] args) {
  6. SpringApplication.run(UserServiceGrayApplication.class, args);
  7. }
  8. }

2.3 传递灰度标签

  1. package com.example.userservicegray.config;
  2. import com.example.globalconfigdemo.global.GlobalVarible;
  3. import feign.RequestInterceptor;
  4. import feign.RequestTemplate;
  5. import jakarta.servlet.http.HttpServletRequest;
  6. import org.springframework.stereotype.Component;
  7. import org.springframework.web.context.request.RequestContextHolder;
  8. import org.springframework.web.context.request.ServletRequestAttributes;
  9. import java.util.Enumeration;
  10. @Component
  11. public class FeignRequestInterceptor implements RequestInterceptor {
  12. @Override
  13. public void apply(RequestTemplate requestTemplate) {
  14. // 从 RequestContextHolder 中获取 HttpServletRequest
  15. ServletRequestAttributes attributes = (ServletRequestAttributes)
  16. RequestContextHolder.getRequestAttributes();
  17. HttpServletRequest request = attributes.getRequest();
  18. if(request.getHeader(GlobalVarible.GRAY_TAG)!=null&&request.getHeader(GlobalVarible.GRAY_TAG)=="true"){
  19. requestTemplate.header(GlobalVarible.GRAY_TAG,"true");
  20. }
  21. }
  22. // @Override
  23. // public void apply(RequestTemplate requestTemplate) {
  24. // // 从 RequestContextHolder 中获取 HttpServletRequest
  25. // ServletRequestAttributes attributes = (ServletRequestAttributes)
  26. // RequestContextHolder.getRequestAttributes();
  27. // HttpServletRequest request = attributes.getRequest();
  28. // Enumeration<String> headerNames = request.getHeaderNames();
  29. // while (headerNames.hasMoreElements()){
  30. // String key = headerNames.nextElement();
  31. // String value = request.getHeader(key);
  32. // requestTemplate.header(key,value);
  33. // }
  34. // }
  35. }

三、网关模块

网关传递灰度发布标识

  1. package com.example.gatewayservice;
  2. import org.springframework.cloud.gateway.filter.GatewayFilterChain;
  3. import org.springframework.cloud.gateway.filter.GlobalFilter;
  4. import org.springframework.core.Ordered;
  5. import org.springframework.http.server.reactive.ServerHttpRequest;
  6. import org.springframework.http.server.reactive.ServerHttpResponse;
  7. import org.springframework.stereotype.Component;
  8. import org.springframework.web.server.ServerWebExchange;
  9. import reactor.core.publisher.Mono;
  10. @Component
  11. public class GatewayFilter implements GlobalFilter, Ordered {
  12. @Override
  13. public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
  14. ServerHttpRequest request= exchange.getRequest();
  15. ServerHttpResponse response= exchange.getResponse();
  16. if(request.getQueryParams().getFirst(GlobalVarible.GRAY_TAG)!=null&&request.getQueryParams().getFirst(GlobalVarible.GRAY_TAG)=="true") {
  17. response.getHeaders().set(GlobalVarible.GRAY_TAG, "true");
  18. }
  19. System.out.println("======================================");
  20. return chain.filter(exchange);
  21. }
  22. @Override
  23. public int getOrder() {
  24. return 0;
  25. }
  26. }

四、自定义负载均衡模块

4.1 自定义负载均衡器

  1. package com.example.globalconfigdemo.global;
  2. import org.apache.commons.logging.Log;
  3. import org.apache.commons.logging.LogFactory;
  4. import org.springframework.beans.factory.ObjectProvider;
  5. import org.springframework.cloud.client.ServiceInstance;
  6. import org.springframework.cloud.client.loadbalancer.*;
  7. import org.springframework.cloud.loadbalancer.core.*;
  8. import org.springframework.http.HttpHeaders;
  9. import reactor.core.publisher.Mono;
  10. import java.util.List;
  11. import java.util.Random;
  12. import java.util.concurrent.atomic.AtomicInteger;
  13. public class GlobalLoadbancer implements ReactorServiceInstanceLoadBalancer {
  14. private static final Log log = LogFactory.getLog(RoundRobinLoadBalancer.class);
  15. private AtomicInteger position;
  16. private String serviceId;
  17. ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;
  18. public GlobalLoadbancer(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider, String serviceId) {
  19. this(serviceInstanceListSupplierProvider, serviceId, (new Random()).nextInt(1000));
  20. }
  21. public GlobalLoadbancer(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider, String serviceId, int seedPosition) {
  22. this.serviceId = serviceId;
  23. this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
  24. this.position = new AtomicInteger(seedPosition);
  25. }
  26. public Mono<Response<ServiceInstance>> choose(Request request) {
  27. ServiceInstanceListSupplier supplier = (ServiceInstanceListSupplier)this.serviceInstanceListSupplierProvider.getIfAvailable(NoopServiceInstanceListSupplier::new);
  28. return supplier.get(request).next().map((serviceInstances) -> {
  29. //此时调用时,将request作为参数传给调用方法,在得到服务实例时通过判断请求头中的标识来返回实例
  30. return this.processInstanceResponse(supplier, serviceInstances,request);
  31. });
  32. }
  33. private Response<ServiceInstance> processInstanceResponse(ServiceInstanceListSupplier supplier, List<ServiceInstance> serviceInstances,Request request) {
  34. //将request 传给调用方法
  35. Response<ServiceInstance> serviceInstanceResponse = this.getInstanceResponse(serviceInstances,request);
  36. if (supplier instanceof SelectedInstanceCallback && serviceInstanceResponse.hasServer()) {
  37. ((SelectedInstanceCallback)supplier).selectedServiceInstance((ServiceInstance)serviceInstanceResponse.getServer());
  38. }
  39. return serviceInstanceResponse;
  40. }
  41. private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances,Request request) {
  42. if (instances.isEmpty()) {
  43. if (log.isWarnEnabled()) {
  44. log.warn("No servers available for service: " + this.serviceId);
  45. }
  46. return new EmptyResponse();
  47. } else if (instances.size() == 1) {
  48. return new DefaultResponse((ServiceInstance)instances.get(0));
  49. } else {
  50. //得到 Request 对象,[通过方法传递参数得到此对象]
  51. //从 Request 对象的 Header 中得到灰度标签
  52. RequestDataContext requestDataContext= (RequestDataContext) request.getContext();
  53. HttpHeaders headers=requestDataContext.getClientRequest().getHeaders();
  54. if(headers.get(GlobalVarible.GRAY_TAG)!=null&&headers.get(GlobalVarible.GRAY_TAG).get(0).equals("true")){
  55. List<ServiceInstance> grayInstance=instances.stream().filter(s->s.getMetadata().get(GlobalVarible.GRAY_TAG)!=null&&s.getMetadata().get(GlobalVarible.GRAY_TAG).equals("true")).toList();
  56. //判断灰度列表不为空
  57. if(grayInstance.size()>0){
  58. instances=grayInstance;
  59. }
  60. }else {
  61. instances=instances.stream().filter(s->s.getMetadata().get(GlobalVarible.GRAY_TAG)==null || !s.getMetadata().get(GlobalVarible.GRAY_TAG).equals("true")).toList();
  62. }
  63. int pos = this.position.incrementAndGet() & Integer.MAX_VALUE;
  64. ServiceInstance instance = instances.get(pos % instances.size());
  65. return new DefaultResponse(instance);
  66. }
  67. }
  68. }

4.2 封装自定义负载均衡器

  1. package com.example.globalconfigdemo.global.config;
  2. import com.example.globalconfigdemo.global.GlobalLoadbancer;
  3. import org.springframework.cloud.client.ServiceInstance;
  4. import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
  5. import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
  6. import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
  7. import org.springframework.context.annotation.Bean;
  8. import org.springframework.core.env.Environment;
  9. public class GllobalLoadbanlancerConfig {
  10. @Bean
  11. public ReactorLoadBalancer<ServiceInstance> reactorServiceInstanceLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) {
  12. String name = environment.getProperty("loadbalancer.client.name");
  13. return new GlobalLoadbancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
  14. }
  15. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/秋刀鱼在做梦/article/detail/890436
推荐阅读
相关标签
  

闽ICP备14008679号