zuul灰度发布功能实现

灰度发布、蓝绿发布、金丝雀发布各是什么意思,可以看这篇http://www.appadhoc.com/blog/product-release-strategy/。

基于eureka、ribbon实现灰度发布,是这一篇要讲的知识。

我们要发布版本了,在不确定正确性的情况下,我们选择先部分节点升级,然后让一些特定的流量进入到这些新节点,完成测试后再全量发布。


我们知道,在eureka中注册各个服务后,如果一个服务有多个实例,那么默认会走ribbon的软负载均衡来进行分发请求。

我们要完成灰度发布,要做的就是修改ribbon的负载策略(rule),通过一些特定的标识,譬如我们可以选择header里带有foo=1的全部路由到金丝雀服务上,其他的还走原来的老版本。或者可以设置个比重,虽然roll个小于4的正数,将等于1的路由到金丝雀,这样就会有1/4的请求到达金丝雀。诸如此类,我们可以定制各种规则来进行灰度测试。

在SpringCloud体系中,完成这件事,模式比较固定,就是根据eureka的metadata进行自定义元数据,然后修改ribbon的Rule规则。

使用很简单,我们直接上例子,注意我这里只发出来目标服务和zuul的代码,eureka的就不放了。eureka很简单,就是一个eureka server项目,什么也没有。

我们的目标服务是User,在User的application.yml里,由于我要启动2个,所以使用不同的端口

application.yml

[html]  view plain  copy
  1. server:  
  2.   port: 8888  
  3. eureka:  
  4.   instance:  
  5.     prefer-ip-address: true  
  6.     metadata-map:  
  7.       lancher: 2  
  8.   client:  
  9.     service-url:  
  10.       defaultZone: http://localhost:10000/eureka/  
application-dev.yml

[html]  view plain  copy
  1. server:  
  2.   port: 8889  
  3. eureka:  
  4.   instance:  
  5.     metadata-map:  
  6.       lancher: 1  
就是那个metadata-map元数据,这是一个map,里面就自定义一些key-value键值对。将来匹配时就用这个键值对。

然后分别启动这两个实例,启动后就有两个user注册到了eureka。

zuul配置:

在zuul项目里添加依赖,https://github.com/jmnarloch/ribbon-discovery-filter-spring-cloud-starter

[html]  view plain  copy
  1. <dependency>  
  2.             <groupId>io.jmnarloch</groupId>  
  3.             <artifactId>ribbon-discovery-filter-spring-cloud-starter</artifactId>  
  4.             <version>2.1.0</version>  
  5.         </dependency>  
这个就是做ribbon的Rule的。

[java]  view plain  copy
  1. package com.example.zuul_route;  
  2.   
  3. import com.netflix.zuul.ZuulFilter;  
  4. import com.netflix.zuul.context.RequestContext;  
  5. import io.jmnarloch.spring.cloud.ribbon.support.RibbonFilterContextHolder;  
  6. import org.springframework.context.annotation.Configuration;  
  7.   
  8. import javax.servlet.http.HttpServletRequest;  
  9.   
  10. import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.*;  
  11.   
  12. /** 
  13.  * @author wuweifeng wrote on 2018/1/17. 
  14.  */  
  15. @Configuration  
  16. public class PreFilter extends ZuulFilter {  
  17.     @Override  
  18.     public int filterOrder() {  
  19.         return PRE_DECORATION_FILTER_ORDER - 1;  
  20.     }  
  21.   
  22.     @Override  
  23.     public String filterType() {  
  24.         return PRE_TYPE;  
  25.     }  
  26.   
  27.     @Override  
  28.     public boolean shouldFilter() {  
  29.         RequestContext ctx = RequestContext.getCurrentContext();  
  30.         // a filter has already forwarded  
  31.         // a filter has already determined serviceId  
  32.         return !ctx.containsKey(FORWARD_TO_KEY)  
  33.                 && !ctx.containsKey(SERVICE_ID_KEY);  
  34.     }  
  35.   
  36.     @Override  
  37.     public Object run() {  
  38.         RequestContext ctx = RequestContext.getCurrentContext();  
  39.         HttpServletRequest request = ctx.getRequest();  
  40.         if (request.getParameter("foo") != null) {  
  41.             // put the serviceId in `RequestContext`  
  42.             RibbonFilterContextHolder.getCurrentContext()  
  43.                     .add("lancher""1");  
  44.         }  else {  
  45.             RibbonFilterContextHolder.getCurrentContext()  
  46.                     .add("lancher""2");  
  47.         }  
  48.           
  49.         return null;  
  50.     }  
  51. }  
这个是zuul的filter,别的无所谓,注意看run方法,RibbonFilterContextHolder.getCurrentContext() .add("lancher", "1");这句话就代表将请求路由到metadata-map里lancher为1的那个服务。

so,很简单,我们就可以在这里定制各种规则了,把符合什么条件的请求,只发送到某个实例。

转自:https://blog.csdn.net/tianyaleixiaowu/article/details/79130646

猜你喜欢

转载自blog.csdn.net/wyxz126/article/details/80611843