一、前言

本文,引入Discovery【探索】微服务框架搭建一个简单的灰度发布demo,Discovery微服务框架源码即在源码,里面根据不同的使用者,有很多demo。如下:

1.1 Discovery【探索】微服务框架指南示例说明

  • 对于入门级玩家,参考指南示例极简版,分支为simple。涉及到指南篇里的灰度路由和发布的基本功能, 参考新手快速入门
  • 对于熟练级玩家,参考指南示例精进版,分支为master。除上述《极简版》功能外,涉及到指南篇里的绝大多数高级功能
  • 对于骨灰级玩家,参考指南示例高级版,分支为premium。除上述《精进版》功能外,涉及到指南篇里的ActiveMQ、MongoDB、RabbitMQ、Redis、RocketMQ、MySQL等高级调用链和灰度调用链的整合

1.2  Discovery【探索】微服务企业级解决方案

① Discovery【探索】微服务企业级解决方案文档

② Discovery【探索】微服务企业级解决方案源码。请访问Gitee镜像获得最佳体验

③ Discovery【探索】微服务企业级解决方案指南示例源码。请访问Gitee镜像获得最佳体验

里面结合各种框架,有很多例子,供使用者参考,这里,仅针对,我们的架构,使用gateway作为网关,nacos作为注册中心,去除里面的配置中心,来实现根据版本来进行全链路灰度发布,demo如下文所述。

二、搭建环境

2.1 构建父工程GrayPublishDemo

2.1.1 框架整体架构图

微服务 灰度发布 微服务灰度发布框架_spring

2.1.2 新建pom

引入discovery框架版本为6.3.2,此版本兼容SpringCloud F版及以上版本

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>GrayPublishDemo</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>consumer</module>
        <module>product</module>
        <module>gateway</module>
    </modules>

    <properties>
        <discovery.version>6.3.2</discovery.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.SR2</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.1.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.0.4.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

</project>

2.2 构建消费者consumer

2.2.1 consumer结构

微服务 灰度发布 微服务灰度发布框架_微服务 灰度发布_02

2.2.2 pom

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>GrayPublishDemo</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>consumer</artifactId>


    <dependencies>
        <!-- 1.注册中心插件 -->
        <dependency>
            <groupId>com.nepxion</groupId>
            <artifactId>discovery-plugin-register-center-starter-nacos</artifactId>
            <version>${discovery.version}</version>
        </dependency>

        <!-- 2.服务的策略编排插件 -->
        <dependency>
            <groupId>com.nepxion</groupId>
            <artifactId>discovery-plugin-strategy-starter-service</artifactId>
            <version>${discovery.version}</version>
        </dependency>
    </dependencies>

</project>

2.2.3 yaml

server:
  port: 4001
spring:
  application:
    name: consumer
  cloud:
    nacos:
      discovery:
        metadata:
          version: 1
        server-addr: localhost:8848

2.2.4 主启动

package com.best;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;


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

2.2.5 业务类

package com.best.controller;

import com.best.rpc.GatewayRpc;
import com.best.rpc.ProductRpc;
import org.springframework.beans.factory.annotation.Autowired;
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;


@RestController
@RequestMapping("/consumer")
public class ConsumerController {

    @Value("${spring.application.name}")
    private String serverName;

    @Value("${server.port}")
    private String serverPort;

    @Value("${spring.cloud.nacos.discovery.metadata.version}")
    private String version;

    @Autowired
    private GatewayRpc gatewayRpc;

    @Autowired
    private ProductRpc productRpc;

    @GetMapping("/product")
    public String getProduct() {

        String consumer = "application name is: 【" + serverName + "】, server port is: 【" + serverPort + "】" + ", version is: 【" + version + "】";

        return  consumer  + " || " + productRpc.getApplicationInfo();
    }

    @GetMapping("/gateway")
    public String getGateway() {

        String consumer = "application name is: 【" + serverName + "】, server port is: 【" + serverPort + "】" + ", version is: 【" + version + "】";

        return  consumer  + " || " + gatewayRpc.getApplicationInfo();
    }
}
package com.best.rpc;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

/**
 * @author Create by Brian on 2019/11/22 12:24
 */
@Component
@FeignClient(name = "gateway")
public interface GatewayRpc {

    @GetMapping("/gateway/service")
    String getApplicationInfo();
}
package com.best.rpc;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

/**
 * @author Create by Brian on 2019/11/25 14:28
 */
@Component
@FeignClient(name = "product")
public interface ProductRpc {

    @GetMapping("/product/service")
    String getApplicationInfo();
}

2.3 构建生产者product

2.3.1 生产者架构图

微服务 灰度发布 微服务灰度发布框架_xml_03

2.3.2 pom

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>GrayPublishDemo</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>product</artifactId>


    <dependencies>
        <!-- 1.注册中心插件 -->
        <dependency>
            <groupId>com.nepxion</groupId>
            <artifactId>discovery-plugin-register-center-starter-nacos</artifactId>
            <version>${discovery.version}</version>
        </dependency>

        <!-- 2.服务的策略编排插件 -->
        <dependency>
            <groupId>com.nepxion</groupId>
            <artifactId>discovery-plugin-strategy-starter-service</artifactId>
            <version>${discovery.version}</version>
        </dependency>
    </dependencies>

</project>

2.3.3 yaml

server:
  port: 3001
spring:
  application:
    name: product
  cloud:
    nacos:
      discovery:
        metadata:
          version: 2
        server-addr: localhost:8848

2.3.4 主启动

package com.best;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;


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

2.3.5 业务类

package com.best.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;


@RestController
@RequestMapping("/product")
public class ProductController {

    @Value("${spring.application.name}")
    private String serverName;

    @Value("${server.port}")
    private String serverPort;

    @Value("${spring.cloud.nacos.discovery.metadata.version}")
    private String version;

    @GetMapping("/service")
    public String getApplicationInfo() {
        return "application name is: 【" + serverName + "】, server port is: 【" + serverPort + "】" + ", version is: 【" + version + "】";
    }
}

2.4 构建网关gateway

2.4.1 gateway结构图

微服务 灰度发布 微服务灰度发布框架_微服务 灰度发布_04

2.4.2 pom

注意这里引入的是,网关的策略编排插件

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>GrayPublishDemo</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>gateway</artifactId>

    <dependencies>
        <!-- 1.注册中心插件 -->
        <dependency>
            <groupId>com.nepxion</groupId>
            <artifactId>discovery-plugin-register-center-starter-nacos</artifactId>
            <version>${discovery.version}</version>
        </dependency>

        <!-- 2.网关的策略编排插件 -->
        <dependency>
            <groupId>com.nepxion</groupId>
            <artifactId>discovery-plugin-strategy-starter-gateway</artifactId>
            <version>${discovery.version}</version>
        </dependency>
    </dependencies>

</project>

2.4.3 yaml

server:
  port: 5001
spring:
  application:
    name: gateway
    strategy:
      gateway:
        header:
          priority: false
  cloud:
    gateway:
      routes:
        - id: consumer
          predicates:
            - Path=/consumer/**
          uri: lb://consumer
        - id: product
          predicates:
            - Path=/product/**
          uri: lb://product
    nacos:
      discovery:
        metadata:
          version: 1
        server-addr: localhost:8848

2.4.4 主启动

package com.best;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;


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

}

2.4.5 业务类

package com.best.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;


@RestController
@RequestMapping("/gateway")
public class GatewayController {

    @Value("${spring.application.name}")
    private String serverName;

    @Value("${server.port}")
    private String serverPort;

    @Value("${spring.cloud.nacos.discovery.metadata.version}")
    private String version;

    @GetMapping("/service")
    public String getApplicationInfo() {
        return "application name is: 【" + serverName + "】, server port is: 【" + serverPort + "】" + ", version is: 【" + version + "】";
    }
}

三、利用postman根据header测试灰度路由

3.1 配置启动

微服务 灰度发布 微服务灰度发布框架_spring_05

启动6个服务

3.2 未加入版本测试

不同send,版本1版本2,轮询访问

微服务 灰度发布 微服务灰度发布框架_微服务 灰度发布_06

3.3 不同服务版本测试

3.3.1 版本路由

header中加入n-d-version:{"consumer":"1","product":"2"}

consumer访问版本1,product访问版本2

微服务 灰度发布 微服务灰度发布框架_微服务 灰度发布_07

3.3.2 版本+权重

header中加入n-d-version-weight: {"consumer":"1=90;2=10", "product":"1=20;2=80"}

实现consumer90%的流量进入版本1,10%流量进入版本2;product 20%的流量进入版本1,80%的流量进入版本2

微服务 灰度发布 微服务灰度发布框架_xml_08

3.4 整体服务版本测试

3.4.1 根据版本

如果所有服务,统一路由到哪个版本,可以简化为

n-d-version: 2

微服务 灰度发布 微服务灰度发布框架_maven_09

四、根据nacos配置测试灰度路由

4.1 加入配置

gitee源码