Spring Cloud微服务网关Zuul灰度发布入门实战

一、灰度发布

灰度发布是指在系统迭代的时候一种平滑过度上线发布方式。灰度发布是在原有的系统的基础上面,额外增加一个新版本,这个新版本包含新上线的需要验证的功能,通过负载均衡引入部分流量到新版本的应用上,如果在这个过程中没有出现问题,便可以平滑地把线上的应用一步步替换成新的版本,这样就完成了一次灰度发布。通过灰度发布的方式可以在用户无感的情况下完成系统发版升级。

二、基于Eureka的metadata实现灰度发布

这里使用一个开源的实现:ribbon-discovery-filter-spring-cloud-starter

在Eureka中有两种metadata:

  • 标准元数据:主要是服务的各种信息。如服务IP、端口、服务健康状态、续约信息等。
  • 自定义的元数据:往Eureka注册的服务可以通过eureka.instance.metadata-map.=来配置,内部就是一个map来保存的。可以配置在远程的服务,也可以随着服务的注册保存到Eureka注册表中。

基于Eureka的元数据实现完成灰度发布的原理是:通过获取Eureka的元数据信息,根据元数据信息的识别,最后在路由规则进行负载均衡。

2.1 新建cloud-service-usercenter

依赖:

	<dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-actuatorartifactId>
        dependency>
        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
            <exclusions>
                <exclusion>
                    <artifactId>spring-boot-starter-tomcatartifactId>
                    <groupId>org.springframework.bootgroupId>
                exclusion>
            exclusions>
        dependency>
        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-undertowartifactId>
        dependency>
        <dependency>
            <groupId>io.undertowgroupId>
            <artifactId>undertow-servletartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
        dependency>
    dependencies>

    <repositories>
        <repository>
            <id>spring-milestonesid>
            <name>Spring Milestonesname>
            <url>https://repo.spring.io/libs-milestoneurl>
            <snapshots>
                <enabled>falseenabled>
            snapshots>
        repository>
    repositories>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
            plugin>
        plugins>
    build>

配置文件:这里通过配置文件配置三份配置,-1随机端口,node1和node2是v1版本,node3是v2版本。

server:
  port: 8877
spring:
  profiles: node1
  application:
    name: usercenter
eureka:
  client:
    serviceUrl:
      defaultZone: http://${eureka.host:127.0.0.1}:${eureka.port:8671}/eureka/
  instance:
    prefer-ip-address: true
    metadata-map:
      version: release

---

server:
  port: 8899
spring:
  profiles: node2
  application:
    name: usercenter
eureka:
  client:
    serviceUrl:
      defaultZone: http://${eureka.host:127.0.0.1}:${eureka.port:8671}/eureka/
  instance:
    prefer-ip-address: true
    metadata-map:
      version: release

---

server:
  port: 8866
spring:
  profiles: node3
  application:
    name: usercenter
eureka:
  client:
    serviceUrl:
      defaultZone: http://${eureka.host:127.0.0.1}:${eureka.port:8671}/eureka/
  instance:
    prefer-ip-address: true
    metadata-map:
      version: gray

Controller:

@RestController
@RequestMapping("user")
public class UsercenterController {

    @Value("${spring.profiles}")
    private String profile;
    @Value("${server.port}")
    private Integer port;

    @GetMapping("list")
    public String list() {
        return "active " + profile + " port " + port;
    }
}

启动类:

@SpringBootApplication
@EnableDiscoveryClient
public class UsercenterApplication {

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

2.2 Zuul网关添加路由和依赖

配置文件:

server:
  port: 88
spring:
  application:
    name: zuul-server
eureka:
  client:
    serviceUrl:
      defaultZone: http://${eureka.host:127.0.0.1}:${eureka.port:8671}/eureka/
  instance:
    prefer-ip-address: true
logging:
  level:
    org.springframework.cloud.netflix: debug
zuul:
  routes:
    service-a:
      path: /usercenter/**
      serviceId: usercenter

依赖:

<dependency>
  <groupId>io.jmnarlochgroupId>
  <artifactId>ribbon-discovery-filter-spring-cloud-starterartifactId>
  <version>2.1.0version>
dependency>

编写灰度发布过滤器:当携带请求gray_switch并且值为open时就会去请求灰度版本的应用。否则就是请求release版本的应用。

现实中我们可以通过使用Nginx,然后将部分流量添加请求头,这样就可以切一部分的流量去做灰度了。

@Component
public class GrayFilter extends ZuulFilter {
    @Override
    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        return FilterConstants.PRE_DECORATION_FILTER_ORDER - 1;
    }

    @Override
    public boolean shouldFilter() {
        RequestContext ctx = RequestContext.getCurrentContext();
        return !ctx.containsKey(FORWARD_TO_KEY) && !ctx.containsKey(SERVICE_ID_KEY);
    }

    @Override
    public Object run() throws ZuulException {
        HttpServletRequest request = RequestContext.getCurrentContext().getRequest();
        String mark = request.getHeader("gray_switch");
        if (StringUtils.isNotBlank(mark) && "open".equals(mark)) {
            RibbonFilterContextHolder.getCurrentContext().add("version", "gray");
        } else {
            RibbonFilterContextHolder.getCurrentContext().add("version", "release");
        }
        return null;
    }
}

2.3 启动测试

分别启动Eureka、Zuul和UsercenterApplication。

在启动UsercenterApplication的使用指定active profile:

  • 例如通过IDEA启动时修改配置Active profiles启动给三个分别设置 node1、node2、node3。

  • 在UsercenterApplication所在的pomx文件下,mvn运行

    mvn spring-boot:run -Dspring-boot.run.profiles=node1

    mvn spring-boot:run -Dspring-boot.run.profiles=node2

    mvn spring-boot:run -Dspring-boot.run.profiles=node3

访问接口时

http://localhost:88/usercenter/user/list

最后

可以关注我的微信公众号,有更多的技术干货文章
在这里插入图片描述

你可能感兴趣的:(Spring,Cloud系列文章,微服务,spring,cloud,微服务,spring,java,spring,boot)