+-
感觉没太大差,但是要自己实现自动刷新serverlist。可以参考ribbon的做法来做。 推荐是使用spring-cloud-loadbalancer,因为ribbon是阻塞的。 官网推荐使用CircuitBreaker, 因为Hystrix 不维护了。CircuitBreaker 只有信号量隔离,可以直接使用threadlocal。
0.参考
文章1 ribbon中使用HystrixRequestVariableDefault的一个注意事项
文章2 SpringCloud灰度发布实践(附源码) zuul实现的可以参考。
1.思路
改造gataway的### Weight Route Predicate Factory,在指定权重的同时指定每个对应权重的服务的版本号。主要需要改写的地方是要在分流之后,将版本号传给ribbon,ribbon在做负载均衡选择的时候,根据传入的版本号,与服务的eureka.matedata中的version匹配,从而达到灰度发布的目的。
gateway的配置类似如下,VersionWeight为重写的断言工厂。
- id: temp_old
uri: lb://TEMPLATE
predicates:
- Path=/temp/**
- VersionWeight=group1, 10, v1
filters:
- StripPrefix=1
- id: temp_new
uri: lb://TEMPLATE
predicates:
- Path=/temp/**
- VersionWeight=group1, 1, v2
filters:
- StripPrefix=1
2.调查改造点
debug后知道了整个请求顺序
客户端-> gateway filter -> LoadBalancerClientFilter -> (如果使用ribbon) RibbonLoadBalancerClient-> (某个Rule) XXXAvoidanceRule -> (对应的 Predicate) XXXAvoidancePredicate
所以选择的服务的关键就是Ribbon的rule和Predicate
步骤
写一个grayContext, 基于threadlocal处理version的上下文传递。 自定义负载策略:负载策略的关键是Rule 和 Predicate, Rule 继承 PredicateBasedRule, Predicate 继承 AbstractServerPredicate, 实现Predicate 中的 apply方法 此方法是负载策略核心(逻辑:从grayContext获取version,与服务的eureka.matedata中的version匹配。匹配上则为目标服务) 改写权重断言策略:改写WeightRoutePredicateFactory,在Factory 分流完成后,把路由中配置的 version 放入到grayContext 中。并且要将vesion 放入到 request的head中,用来向下传递。上面是对gateway的改造,经过改造后,gateway分发的时候就根据version能指定请求的服务器,接下来是微服务间通过fegin或者restTemplate调用时的改造,目的是将version继续往下传递
对request请求拦截:在微服务中对request请求进行拦截,将request中的version放到grayContext中 对fegin添加拦截器:实现RequestInterceptor,从grayContext中取出version放在头部中。fegin的loadbanced也是基于ribbon的,所以使用自定义负载策略进行分发,策略和gateway一致。 如果使用restTemplate,添加拦截器:实现ClientHttpRequestInterceptor,从grayContext中取出version放在头部中。这样就将version串联起来,从而实现了指定流量到对应的服务。
注意点
如果断路器使用Hystrix,要注意Hystrix用信号量隔离,没问题,如果使用线程池隔离,我们基于threadlocal处理version就无效了,
hystrix有提供对应的方法 使用 HystrixRequestVariableDefault
参考文章1这篇文章中提到的使用方式,能理解HystrixRequestVariableDefault是个怎样的用法,其作用和threadlocal类似。
3.待解决问题
不使用ribbon的情况,引入spring-cloud-loadbalancer, loadbalancer 和 ribbon差蛮多,不支持自动刷新serverlist,只有一个RoundRobinLoadBalancer。 会使用ReactiveLoadBalancerClientFilter,要通过实现ReactorServiceInstanceLoadBalancer 接口 来实现负载策略感觉没太大差,但是要自己实现自动刷新serverlist。可以参考ribbon的做法来做。 推荐是使用spring-cloud-loadbalancer,因为ribbon是阻塞的。 官网推荐使用CircuitBreaker, 因为Hystrix 不维护了。CircuitBreaker 只有信号量隔离,可以直接使用threadlocal。