基于springcloud的灰度实现方案

Posted 鱼翔空

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于springcloud的灰度实现方案相关的知识,希望对你有一定的参考价值。

前言

目前所有的服务都是基于springboot/springcloud体系,注册中心使用eureka。

背景:

  • 新的功能上线后,特别是大版本上线,不能完全保证新功能的质量,特别是对历史用户,数据差异性比较大,又无法复现;

  • 为了测试哪套流程的转化率比较高;

想要的效果

图片

这里就会有以下几个问题:

  1. 如果识别是灰度用户?

  2. 如何识别是灰度服务?

  3. 如何让灰度用户走灰度服务?

  4. 如何让灰度标签传递下去?

系统访问如下:

图片

  1. 用户可以通过网关打上灰度标签;

  2. 用户可以根据网关路由是走api还是走service;

  3. 用户可以根据自定义路由走灰度还是走普通服务;

**如何识别灰度用户?
**

用户在网关里鉴权完成后,根据用户的属性来动态判断;

目前项目里写死了三个用户信息,token分别是:abc,bcd,其他;

其中:

abc: userId = 1 name = ‘yxkong’ mobile = ‘15600000269’

bcd: userId = 901 name = ‘鱼翔空’ mobile = ‘15600000279’

其他:userId = 901 name = ‘火星’ mobile = ‘15600000270’

    private String getUserInfo(String token){
        if("abc".equals(token)){
            return "{\\"userId\\":\\"1\\",\\"name\\":\\"yxkong\\",\\"mobile\\":\\"15600000269\\"}";
        }else if("bcd".equals(token)){
            return "{\\"userId\\":\\"901\\",\\"name\\":\\"鱼翔空\\",\\"mobile\\":\\"15600000279\\"}";
        }else {
            return "{\\"userId\\":\\"901\\",\\"name\\":\\"火星\\",\\"mobile\\":\\"15600000270\\"}";
        }
    }

灰度拦截策略是:

mobile 取模是6 或9

userId 大于等于900

 rules.add(new LoadBalancerRule("mobile","mod10","6,9","and"));
 rules.add(new LoadBalancerRule("userId","gte","900","and"));
    

如何识别灰度服务?

利用eureka的metadata-map自定义元数据

eureka:
  instance:
    metadata-map:
      version: 2.0
      label: gray
# 访问地址(注意,postman访问最好,或者curl,直接chrome访问把xml都过滤l )
http://127.0.0.1:8765/eureka/apps/

图片

可以参考下 EurekaInstanceConfigBean,在 instance配置中有个metadataMap 这里可以放置自定义的元数据

package org.springframework.cloud.netflix.eureka;
@ConfigurationProperties("eureka.instance")
public class EurekaInstanceConfigBean implements CloudEurekaInstanceConfig, EnvironmentAware {
    private int leaseRenewalIntervalInSeconds = 30;
    private int leaseExpirationDurationInSeconds = 90;
    private String virtualHostName = "unknown";
    private String instanceId;
    private String secureVirtualHostName = "unknown";
    private String aSGName;
    private Map<String, String> metadataMap = new HashMap();
}    

如何让灰度用户走灰度服务?

重写ribbon的RoundRobinRule负载均衡策略,在负载均衡的时候,走到对应的服务上。

1,判断是否是灰度用户;
2,拿到灰度服务进行路由;

如何让灰度标签传递下去?

通过spring的Interceptor在进入spring的接口请求时,将灰度标签从header中获取并初始化到HystrixRequestContext中,本质上是保存在ThreadLocal中

@Configuration
@ConditionalOnClass(Servlet.class)
public class ServletAutoConfiguration {
    @Bean
    @ConditionalOnClass(WebHandler.class)
    public WebMvcConfigurer configurer() {
        return new WebConfig();
    }

    class WebConfig implements WebMvcConfigurer {
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(interceptor()).addPathPatterns("/**");
        }

        private HandlerInterceptor interceptor() {
            return new HandlerInterceptor() {
                @Override
                public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
                    GrayHolder.initHystrixRequestContext(request.getHeader(GrayHolder.LABEL_KEY),request.getHeader(GrayHolder.VERSION_KEY));
                    return true;
                }

                @Override
                public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
                    GrayHolder.shutdownHystrixRequestContext();
                }
            };
        }
    }
}

如果觉得对你有帮助,请关注公众号:5ycode,后续会不断更新哦

公众号图片

以上是关于基于springcloud的灰度实现方案的主要内容,如果未能解决你的问题,请参考以下文章

基于springcloud的灰度实现方案

feign构建与调用全流程分析

SpringCloud实战(十七)-基于Ribbon动态路由实现:调用链控制/版本控制/灰度发布(粒度更细,可以控制到每一个微服务模块版本的路由)

SpringCloud实战(十七)-基于Ribbon动态路由实现:调用链控制/版本控制/灰度发布(粒度更细,可以控制到每一个微服务模块版本的路由)

SpringCloud系列十一:SpringCloudStream(SpringCloudStream 简介创建消息生产者创建消息消费者自定义消息通道分组与持久化设置 RoutingKey)(代码片段

基于Istio的灰度发布架构方案实践之路