zoukankan      html  css  js  c++  java
  • 使用网关zuul完成灰度发布

    环境

    java 1.8

    springboot 2.3.0.RELEASE

    spring-cloud.version Hoxton.SR5

    背景:实现 zuul->服务 的灰度发布,实现不同的用户固定访问不同的服务

    思路:使用zuul的过滤器Filter,在路由的时候根据灰度规则,选择一个合适的服务

    zuul服务配置

    pom.xml配置如下

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.3.0.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.dandan</groupId>
        <artifactId>cloud-zuul</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>cloud-zuul</name>
        <description>Demo project for Spring Boot</description>
        <properties>
            <java.version>1.8</java.version>
            <spring-cloud.version>Hoxton.SR5</spring-cloud.version>
        </properties>
        <dependencies>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            </dependency>
    
            <!--zuul -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
    
    
            <!-- mysql:MyBatis相关依赖 -->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>2.0.0</version>
            </dependency>
    
            <!-- mysql:mysql驱动 -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
            </dependency>
    
            <!-- mysql:阿里巴巴数据库连接池 -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.12</version>
            </dependency>
    
            <!-- 实现通过 metadata 进行灰度路由 -->
            <dependency>
                <groupId>io.jmnarloch</groupId>
                <artifactId>ribbon-discovery-filter-spring-cloud-starter</artifactId>
                <version>2.1.0</version>
            </dependency>
    
        </dependencies>
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>${spring-cloud.version}</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>                
                </plugin>
            </plugins>
        </build>
    
    </project>

    application.yml配置

    server:
      port: 9100
    
    spring:
      application:
        name: cloud-zuul
      #数据库连接配置
      datasource:
        #配置当前使用的数据源的操作类型
        type: com.alibaba.druid.pool.DruidDataSource
        #配置MySQL的驱动程序类
        driver-class-name: com.mysql.cj.jdbc.Driver
        #数据库连接地址
        url: jdbc:mysql://192.168.1.113:3306/online-taxi-three?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
        #数据库连接用户名
        username: root
        #数据库连接密码
        password: 123456
        #进行数据库连接池的配置
        dbcp2:
          #初始化提供的连接数
          initial-size: 5
          #数据库连接池的最小维持连接数
          min-idle: 5
          #最大的连接数
          max-total: 5
          #等待连接获取的最大超时时间
          max-wait-millis: 200
          validation-query: SELECT 1
          test-while-idle: true
          test-on-borrow: false
          test-on-return: false
    
    #mybatis配置
    mybatis:
      mapper-locations:
        - classpath:mapper/*.xml
    
    eureka:
      client:
        service-url:
          defaultZone: http://eureka-7900:7900/eureka
      instance:
        hostname: localhost
        instance-id: online-taxi-zuul

    在启动类开启网关代理服务

    @SpringBootApplication
    @EnableZuulProxy
    public class CloudZuulApplication {
        public static void main(String[] args) {
            SpringApplication.run(CloudZuulApplication.class, args);
        }
    }

    zuul过滤器部分代码

    import com.netflix.zuul.ZuulFilter;
    import com.netflix.zuul.context.RequestContext;
    import com.netflix.zuul.exception.ZuulException;
    import io.jmnarloch.spring.cloud.ribbon.support.RibbonFilterContextHolder;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
    import org.springframework.stereotype.Component;
    
    import javax.servlet.http.HttpServletRequest;
    
    /**
     * @version 1.0
     * @author: zheaven
     * @date: 2021/11/3 13:30
     */
    @Component
    public class GrayFilter extends ZuulFilter {
        @Override
        public String filterType() {
            return FilterConstants.ROUTE_TYPE;
        }
    
        @Override
        public int filterOrder() {
            return 0;
        }
    
        @Override
        public boolean shouldFilter() {
            return true;
        }
    
        @Override
        public Object run() throws ZuulException {
            RequestContext currentContext = RequestContext.getCurrentContext();
            HttpServletRequest request = currentContext.getRequest();
    
            int userId = Integer.parseInt(request.getHeader("userId"));
            // 根据用户id 查 规则  查库 meta_version=v1, metadata-map
    
            // 1,2是从数据库中查出来的
            // 金丝雀
            if (userId == 1){
                RibbonFilterContextHolder.getCurrentContext().add("version","v1");
                // 普通用户
            }else if (userId == 2){
                RibbonFilterContextHolder.getCurrentContext().add("version","v2");
            }
    
            return null;
        }
    }

    数据库sql

    CREATE TABLE `common_gray_rule` (
      `id` int(16) NOT NULL,
      `user_id` int(16) DEFAULT NULL,
      `service_name` varchar(32) DEFAULT NULL,
      `meta_version` varchar(32) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='模拟灰度发布';
    
    INSERT INTO `common_gray_rule`(`id`, `user_id`, `service_name`, `meta_version`) VALUES (1, 1, 'service-sms', 'v1');

    网关zuul对应要访问的服务 service-sms

    pom.xml配置

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>

    application.yml配置

    # 可以在http://localhost:7900/eureka/apps上查到metadata-map里面的自定义标签数据
    # 在idea中配置两台service-sms服务,只为了方便启动,如果想配置成两个单独的服务,可稍加修改
    ---
    spring:
      profiles: v1
    server:
      port: 8091
    eureka:
      instance:
        metadata-map:
          version: v1
          a: a1
    
    ---
    spring:
      profiles: v2
    server:
      port: 8092
    eureka:
      instance:
        metadata-map:
          version: v2
          a: a2
    ---
    spring:
      application:
        name: service-sms
    
    eureka:
      client:
        service-url:
          # 默认从第一个server拉取注册表,失败后找第二台,重试次数为3次,配置的第四个server无效
          # 建议每个服务的server顺序不一致,防止第一个server压力过大
          defaultZone: http://localhost:7900/eureka
          #,http://localhost:7901/eureka,http://localhost:7902/eureka
        # 从server拉取注册表的间隔时间
        registry-fetch-interval-seconds: 30
        # 是否向eureka服务器注册信息,默认是true
        enabled: true
      instance:
        # client续约的间隔时间,默认是30s
        lease-renewal-interval-in-seconds: 30

    启动类

    @SpringBootApplication
    public class ServiceSmsApplication {
        public static void main(String[] args) {
            SpringApplication.run(ServiceSmsApplication.class, args);
        }
    }

    测试controller类

    package com.dandan.servicesms.controller;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import javax.servlet.http.HttpServletRequest;
    
    @RestController
    @RequestMapping("/test")
    public class ServiceSmsTestController {
    
        @Value("${server.port}")
        private String port;
    
        @GetMapping("/sms-test")
        public String test(){
    
            return "sms-test:"+port;
        }
    }

    cloud-eureka服务

    pom.xml配置

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.3.0.RELEASE</version>
            <relativePath/> 
        </parent>
        <groupId>com.dandan</groupId>
        <artifactId>cloud-eureka</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>cloud-eureka</name>
        <description>Demo project for Spring Boot</description>
        <properties>
            <java.version>1.8</java.version>
            <spring-cloud.version>Hoxton.SR4</spring-cloud.version>
        </properties>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
            </dependency>
        </dependencies>
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>${spring-cloud.version}</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>

    application.yml

    这里是多个eureka配置,启动一个即可

    spring:
      application:
        name: cloud-eureka
    
    eureka:
      client:
        register-with-eureka: false
        fetch-registry: true
        service-url:
          # 两个节点集群搭建只写对方的访问路径
          # 三个节点以上的集群搭建必须全部写上
          # eureka集群搭建 https://docs.spring.io/spring-cloud-netflix/docs/3.0.3/reference/html/#spring-cloud-eureka-server-peer-awareness
          defaultZone: http://localhost:7900/eureka,http://localhost:7901/eureka,http://localhost:7902/eureka
      server:
        # 自我保护看自己情况
        enable-self-preservation: true
        # 续约阈值,和自我保护相关
        renewal-percent-threshold: 0.85
        # server剔除过期服务的时间间隔
        eviction-interval-timer-in-ms: 1000
        # 是否开启readOnly读缓存
        use-read-only-response-cache: true
        # 关闭 readOnly
        response-cache-update-interval-ms: 1000
    
    ---
    spring:
      profiles: 7900
    server:
      port: 7900
    eureka:
      instance:
        hostname: eureka-7900
    
    ---
    spring:
      profiles: 7901
    server:
      port: 7901
    eureka:
      instance:
        hostname: eureka-7901
    
    ---
    spring:
      profiles: 7902
    server:
      port: 7902
    eureka:
      instance:
        hostname: eureka-7902

    启动类

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
    
    @SpringBootApplication
    @EnableEurekaServer
    public class CloudEurekaApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(CloudEurekaApplication.class, args);
        }
    
    }

    配置完成之后启动 eureka、zuul、service-sms服务,发送请求

    http://localhost:9100/service-sms/test/sms-test

    header中配置{userId:1}的访问如下配置的服务

    eureka:
      instance:
        metadata-map:
          # eureka提供自定义的键值对
          version: v1

    不需要启停服务,实时修改eureka上对应服务的自定义元数据 metadata-map

    # PUT localhost:8761/eureka/apps/{spring.application.name}/{服务实例名}/metadata?version=v2
    localhost:7900/eureka/apps/service-sms/windows10.microdone.cn:service-sms:8091/metadata?version=v2

    官网链接:https://github.com/Netflix/eureka/wiki/Eureka-REST-operations

     通过http://localhost:7900/eureka/apps上查看metadata-map里面的自定义标签数据是否改变

  • 相关阅读:
    vim 学习笔记系列(前言)
    12306网站推出图片验证 反破解
    如何提升电脑的速度(五年时间收集各家精华,绝对史上最全)
    电脑维修和维护 毕业总结及经验报告
    留学生 电脑安全与维护手册 (留学须知)
    Progress数据库配置与应用
    润乾报表与DERBY数据库的创建连接详解
    图形报表部署在Linux下出现乱码解决办法
    sqlserver为数据库表增加自增字段
    五种常用web服务器jvm参数设置
  • 原文地址:https://www.cnblogs.com/zheaven/p/15506972.html
Copyright © 2011-2022 走看看