zoukankan      html  css  js  c++  java
  • zuul网关实现灰度发布

    本文使用zuul网关实现灰度发布,包括了网关到服务、服务到服务的灰度。项目gitee:https://gitee.com/menbbo/gray-demo.git

    服务部署可分为三种方式

    1)蓝绿发布

      蓝绿发布是通过冗余的方式来解决部署问题,生产环境为绿色配置,冗余的服务为蓝色配置。在部署服务时,首先在冗余服务器上部署最新代码,由部分用户使用,

    若使用没有问题,则通过负载均衡将所有用户请求转发到冗余服务器中,即冗余的服务转变为生产环境服务。优点是无需停机部署,服务回滚方便。缺点耗费服务器资源。

    2)滚动发布

      滚动发布指每次只部署一个或多个服务,直到服务部署完成为止。优点:用户无感知,平滑过渡;相比蓝绿发布节省服务器资源。缺点:部署复杂,且时间长;遇到

    问题回滚比较复杂。

    3)灰度发布

      只升级部分服务,让少量用户访问新部署的服务,其他用户使用老服务,用户反馈无误后,整个集群部署,将用户迁移到新服务上来。优点:在灰度时即可发现问题及

    时处理,保证系统稳定性;如果出现问题,影响范围小;用户无感知,过渡平滑。

    灰度发布实现步骤:

    1)定义规则:哪些用户可以访问灰度环境,比如按百分比(10%的用户可以访问灰度),或让固定用户先体验灰度环境;

    2)利用网关实现路由策略,即网关到服务的路由;

    3)服务与服务之间的调用使用ribbon实现灰度规则。

    代码实现

    代码使用zuul网关实现,项目包括了zuul、im、search三个服务,im服务调用search服务,具体实现如下。

    1.引入maven依赖,关键依赖

      <dependency>
                <groupId>io.jmnarloch</groupId>
                <artifactId>ribbon-discovery-filter-spring-cloud-starter</artifactId>
                <version>2.1.0</version>
     </dependency>        
    <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-zuul</artifactId>
                <version>1.4.6.RELEASE</version>
     </dependency>
    

    2.application.properties配置文件进行配置

    server.port=9090
    
    spring.application.name=zuul
    #注册中心
    eureka.client.service-url.defaultZone=http://localhost:8761/eureka
    eureka.instance.prefer-ip-address=true
    eureka.client.registerWithEureka=true 
    #zuul网关路由 前缀
    zuul.routes.prefix=/zuul
    zuul.routes.im.path=/im/**
    #im代表自定义服务
    zuul.routes.im.service-id=im
    #false不会截取  true截取前缀
    zuul.routes.im.stripPrefix=true
    
    #http://localhost:9090/zuul/im/index
    

    3.GrayFilter过滤器实现网关到服务的灰度规则

    @Component
    public class GrayFilter extends ZuulFilter {
        private static final String GRAY = "gray";
        @Override
        public String filterType() {
            return FilterConstants.PRE_TYPE;
        }
    
        @Override
        public int filterOrder() {
            return 0;
        }
    
        @Override
        public boolean shouldFilter() {
            //是否开启过滤
            return true;
        }
    
        @Override
        public Object run() throws ZuulException {
            //实现灰度逻辑
            //前端在请求头中携带灰度标识字段
            //服务注册时加入metadata数据,代表该服务节点为灰度节点
            //首先从头部中获取标识
            RequestContext currentContext = RequestContext.getCurrentContext();
            HttpServletRequest request = currentContext.getRequest();
            String header = request.getHeader("gray_header");
            //将灰度的请求转发到meataData中forward为1的服务
            if(StringUtils.equals(header,GRAY)){
                RibbonFilterContextHolder.getCurrentContext().add("forward","1");
            }else {
                RibbonFilterContextHolder.getCurrentContext().add("forward","2");
            }
            return null;
        }
    }
    

    4.im、search服务启动时注册metadata到注册中心

    eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
    eureka.client.enabled=true
    #eureka.instance.hostname=localhost
    #eureka.instance.instance-id=im
    #灰度端口
    server.port=8081
    #生产端口
    #server.port=8082
    spring.application.name=im
    #灰度发布需要metadata
    #灰度为1
    eureka.instance.metadata-map.forward=1
    
    eureka.client.service-url.defaultZone=http://localhost:8761/eureka
    server.port=8089
    spring.application.name=search
    
    #灰度为1
    eureka.instance.metadata-map.forward=1

    5.实现服务到服务的灰度规则

    /**
     *  定义服务间灰度调用规则
     */
    @Component
    public class GrayRule extends AbstractLoadBalancerRule {
    
        private static final String GRAY = "gray";
        private static final String GRAY_HEADER = "forward";
        private static final String GRAY_VALUE = "1";
        private Logger logger = LoggerFactory.getLogger(this.getClass());
    
        @Override
        public void initWithNiwsConfig(IClientConfig iClientConfig) {
    
        }
    
        @Override
        public Server choose(Object o) {
            ILoadBalancer loadBalancer = getLoadBalancer();
            return this.choose(loadBalancer);
        }
    
        private Server choose(ILoadBalancer lb){
            Server server = null;
            if (server==null){
           //获取请求头中的参数,具体实现在gitee Map<String, String> stringStringMap = GrayRibbonParamater.get(); String grayParmater = null; if(stringStringMap!=null){ grayParmater = stringStringMap.get("gray_header"); } //获得可到达的服务 List<Server> reachableServers = lb.getReachableServers(); for (Server reachableServer : reachableServers) { //获取服务的metadata Map<String, String> metadata = ((DiscoveryEnabledServer) reachableServer).getInstanceInfo().getMetadata(); if(StringUtils.equals(metadata.get(GRAY_HEADER),GRAY_VALUE)&&StringUtils.equals(grayParmater,GRAY)){ return reachableServer; } } } return server; } }

      

      

      

      

      

  • 相关阅读:
    [转] 余国藩:人文学科何以不是科学
    [openssl][nginx] 使用openssl模拟ssl/tls客户端测试nginx stream
    [openssl] 使用openssl生成证书
    [bluez] linux下蓝牙鼠标的延迟问题
    很好的一篇文章讲epoll
    [ipsec][strongswan] VirtualPN隧道网络加速FEC(forward error correction)
    [ipsec][crypto] ike/ipsec与tls的认证机制比较
    [ipsec][crypto] 有点不同的数字证书到底是什么
    [ike][ipsec] child sa rekey机制的细节分析
    [dev][nginx] 在阅读nginx代码之前都需要准备什么
  • 原文地址:https://www.cnblogs.com/menbo/p/14855582.html
Copyright © 2011-2022 走看看