SpringCloud灰度发布

一: 调用链分析

请求==>网关==>服务Resttemplate调用==>服务
请求==>网关==>服务Fegin调用==>服务

无论是通过Resttemplate还是Fegin的方式进行服务间的调用,他们都会从Ribbon选择一个服务实例返回


二:调用链详细步骤

  1. 用户请求首先到达Nginx然后转发到网关,此时网关拦截器会根据用户携带请求token解析出对应的userId

  2. 网关从配置中心拉取灰度用户列表,然后根据灰度用户策略判断该用户是否是灰度用户。如是,则给该请求添加请求头线程变量添加信息version=xxx;若不是,则不做任何处理放行

  3. 在网关拦截器执行完毕后,网关在进行转发请求时会通过负载均衡器Ribbon。

  4. 负载均衡Ribbon被重写。当请求到达时候,Ribbon会取出网关存入线程变量值
    version
    。于此同时,Ribbon还会取出所有缓存的服务列表(定期从eureka刷新获取最新列表)及其该服务的metadata-map信息。然后取出服务metadata-map的version信息与线程变量version进行判断对比,若值一直则选择该服务作为返回。若所有服务列表的version信息与之不匹配,则返回null,此时Ribbon选取不到对应的服务则会报错!

  5. 当服务为非灰度服务,即没有version信息时,此时Ribbon会收集所有非灰度服务列表,然后利用Ribbon默认的规则从这些非灰度服务列表中返回一个服务。

  6. 网关通过Ribbon将请求转发到consumer服务后,可能还会通过fegin或resttemplate调用其他服务,如provider服务。但是无论是通过fegin还是resttemplate,他们最后在选取服务转发的时候都会通过Ribbon。

  7. 那么在通过fegin或resttemplate调用另外一个服务的时候需要设置一个拦截器,将请求头version=xxx给带上,然后存入线程变量。

  8. 在经过fegin或resttemplate 的拦截器后最后会到Ribbon,Ribbon会从线程变量里面取出version信息。然后重复步骤(4)和(5)


小结

  1. 将注册中心的灰度服务打上标识
eureka可以使用eureka.instance.metadata-map配置
备注:
Eureka的元数据有两种,分别为标准元数据和自定义元数据。
标准元数据:主机名、IP地址、端口号、状态页和健康检查等信息,这些信息都会被发布在服务注册表中,用于服务之间的调用。
自定义元数据:自定义元数据可以使用eureka.instance.metadata-map配置,这些元数据可以在远程客户端中访问,但是一般不会改变客户端的行为,除非客户端知道该元数据的含义

  1. 请求到达网关时获取灰度用户,对应的灰度用户在请求头里设置上灰度标识
SpringGateWay过滤器GlobalFilter 
Dubbo过滤器Filter
Zuul过滤器ZuulFilter 

  1. 路由或者负载均衡器获取服务列时,根据灰度标识,获取对应的服务
resttemplate拦截器ClientHttpRequestInterceptor
fegin拦截器RequestInterceptor

Ribbon自定义负载均衡ZoneAvoidanceRule
Ribbon详细扩展点可参考前面文章

public class GrayMetadataRule extends ZoneAvoidanceRule {
   // 略....
    @Override
    public Server choose(Object key) {
        //1.从线程变量获取请求头里获取version信息
        String version = xxx;
        
       //2.获取服务实例列表
        List serverList = this.getPredicate().getEligibleServers(this.getLoadBalancer().getAllServers(), key);
        
       //3.循环serverList,选择version匹配的服务并返回
                for (Server server : serverList) {
            Map metadata = ((DiscoveryEnabledServer) server).getInstanceInfo().getMetadata();

            String metaVersion = metadata.get("version);
            if (!StringUtils.isEmpty(metaVersion)) {
                if (metaVersion.equals(hystrixVer)) {
                    return server;
                }
            }
        }
    }
}

你可能感兴趣的:(SpringCloud灰度发布)