基于dubbo版本号实现服务灰度发布

前言

灰度发布这个词对很多同学来说并不陌生,灰度的概念其实是非常广泛的,不能仅仅停留在服务器层面

举例来说,你开发的软件上个版本是V1.0,本次即将发布的是V2.0,但稍有经验的同学应该都知道,如果新版本的功能改动非常大,但是这种改动还必须要经过用户的使用检验,任何的产品都可能存在bug,为了发布出去之后一旦有问题能够快速回退,切换到之前稳定的版本,这个过程就需要用到灰度发布;

在这里插入图片描述

类似的场景还有很多,大家熟悉的游戏公测也是如此,先让一部分种子用户试用新的版本,一旦当公测达到了预期的标准,然后将新版本的服务全部放开

关于灰度发布的理论方面的扩展本篇不过多展开,网上可以查询的资料非常多,本篇以实战开发微服务中遇到的灰度发布场景,以一个实际的技术解决方案为例来进行说明,如果利用dubbo的版本号实现后端服务的灰度发布

前置准备

zk服务,如果已经安装过,只需要启动即可

本篇技术栈

springboot+dubbo

dubbo版本号说明

使用过dubbo做微服务治理的同学对dubbo的版本号控制应该不陌生,dubbo提供了版本号帮助开发者实现对不同版本号下服务的精细控制

举例来说,已经发不出去的dubbo服务版本号是1.0.0,属于稳定版的服务,而2.0.0尚在开发中还没有完成,于是对外提供出去的版本号仍旧是1.0.0,而内部各个服务间依赖的版本号可以使用2.0.0,这个就是版本号的一个实际使用场景

工程环境搭建

演示工程结构如下所示,对使用过dubbo的同学对这个结构应该不陌生,就不做过多说明了
在这里插入图片描述
1、pom依赖

        <dependencies>
        	<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>com.congge</groupId>
            <artifactId>dubbo-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba.boot</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>0.2.0</version>
        </dependency>

    </dependencies>

2、consumer端配置文件

扫描二维码关注公众号,回复: 13274298 查看本文章

#服务名称
spring.application.name=consumer
#服务启动端口号
server.port=8100
## Dubbo 服务名称  ==> java.lang.reflect.InvocationTargetException: null 没有这项配置会报错,无法注册到zookeeper
dubbo.application.name=consumer
## Dubbo 服务端口号
dubbo.protocol.port=20888
## Dubbo 服务注册地址
dubbo.registry.address=zookeeper://127.0.0.1:2181
## Dubbo 服务扫描包路径
dubbo.scan.base-packages=com.congge
## Dubbo 服务是否注册到注册中心
dubbo.registry.register=true

dubbo.consumer.version=1.0.0
dubbo.consumer.check=false

3、provider端配置文件

#项目启动端口号
server.port=8101
# Dubbo 服务消费者配置
dubbo.application.name=provider1
# Dubbo 扫描包的路径
dubbo.scan.basePackages=com.congge.service.impl
# Dubbo 注册id
dubbo.registry.id=provider1
# Dubbo 服务端口号
dubbo.protocol.port=20881
# Dubbo 注册中心地址
dubbo.registry.address=zookeeper://127.0.0.1:2181

dubbo.provider.version=1.0.0

这里只列举了其中一个provider的配置文件,另一个基本一样,注意本篇是演示多个provider基于同一个服务接口提供不同版本,最后的dubbo.provider.version这个配置的版本号需要不一样

4、dubbo-api中提供一个服务接口

public interface SoftService {

    String softInfo(String name);
}

5、dubbo-provider中的服务实现

import com.alibaba.dubbo.config.annotation.Service;
import com.congge.service.SoftService;

@Service
public class SoftServiceImpl implements SoftService {

    @Override
    public String softInfo(String name) {
        return "v1 :" + name;
    }
}

6、dubbo-consumer中提供一个web接口

这里为了演示版本号的不同,使用了两个不同的实现类,在不同的实现类调用不同的provider的服务

在这里插入图片描述

ProviderService1

import com.alibaba.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Service;

@Service
public class ProviderService1 {

    @Reference(version = "1.0.0")
    private SoftService softService;

    public String getSoftInfo(String info){
        return softService.softInfo(info);
    }

}

ProviderService2

@Service
public class ProviderService2 {

    @Reference(version = "2.0.0")
    private SoftService softService;

    public String getSoftInfo(String info){
        return softService.softInfo(info);
    }

}

SoftController


import com.congge.service.ProviderService1;
import com.congge.service.ProviderService2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/softs")
public class SoftController {

    @Autowired
    private ProviderService1 providerService1;

    @Autowired
    private ProviderService2 providerService2;

    //http://localhost:8100/softs/get/info?info=hello&version=1
    @GetMapping("/get/info")
    public String softInfo(@RequestParam("info")String info,int version){
        if(version==1){
            return providerService1.getSoftInfo(info);
        }
        if(version==2){
            return providerService2.getSoftInfo(info);
        }
        return "default";
    }

}

启动3个工程,并提前启动zookeeper服务,浏览器分别访问:

  • http://localhost:8100/softs/get/info?info=hello&version=1
  • http://localhost:8100/softs/get/info?info=hello&version=2

效果展示

在这里插入图片描述
在这里插入图片描述
以上就演示了基于版本号控制不同的流量访问不同的服务的目的,事实上,在真实的环境中,接口是由前端进行调用的,那么可以把相关的规则设定好,由前端读取后端的配置文件,即为了达到不同版本灰度发布的目的,将控制灰度的接口通过配置文件的方式写入到中央配置文件中,一旦需要切换,我们只需要修改配置文件既可以达到快速切换服务的目的

基于权重的灰度发布控制

上面讲述了使用版本号对不同服务接口的控制,但某些情况下,有这么一种场景,我们不想直接从一个版本切换到另一个版本,这个毕竟代价有点大,那么可以考虑,使用同一个服务接口,一部分流量打到之前的服务上,一部分服务打到新的服务上,这个该怎么实现呢?

这个场景可以考虑使用dubbo提供的权重配置打到目的

仍然以上面搭建的工程为例,我们只需要在dubbo-provider1 和 dubbo-provider2 中添加关于权重的配置,并将版本号置为相同即可

dubbo-provider1 配置文件


#项目启动端口号
server.port=8101
# Dubbo 服务消费者配置
dubbo.application.name=provider1
# Dubbo 扫描包的路径
dubbo.scan.basePackages=com.congge.service.impl
# Dubbo 注册id
dubbo.registry.id=provider1
# Dubbo 服务端口号
dubbo.protocol.port=20881
# Dubbo 注册中心地址
dubbo.registry.address=zookeeper://127.0.0.1:2181

dubbo.provider.version=1.0.0
dubbo.provider.weight=2

dubbo-provider2 配置文件


#项目启动端口号
server.port=8102
# Dubbo 服务消费者配置
dubbo.application.name=provider2
# Dubbo 扫描包的路径
dubbo.scan.basePackages=com.congge.service.impl
# Dubbo 注册id
dubbo.registry.id=provider2
# Dubbo 服务端口号
dubbo.protocol.port=20882
# Dubbo 注册中心地址
dubbo.registry.address=zookeeper://127.0.0.1:2181

dubbo.provider.version=1.0.0
dubbo.provider.weight=9

dubbo-cnsumer端接口改造

新增一个方法

    @Reference
    private SoftService softService;
	
	//http://localhost:8100/softs/common/info?info=hello
    @GetMapping("/common/info")
    public String softCommonInfo(@RequestParam("info") String info) {
        return softService.softInfo(info);
    }

再次启动3个模块的服务,浏览器反复调用下面的接口:

  • http://localhost:8100/softs/common/info?info=hello

在这里插入图片描述
在这里插入图片描述

通过后台打印日志的对比,可以发现,由于dubbo-provider2给的权重比dubbo-provider1更高,相同的环境下,被调用的概率将会更大

利用这种特性,我们可以设想,为了保险起见,新上线的服务可以考虑分配少量的权重,而让更多的流量打到之前的版本上面,这样经过一段时间的生产测试,逐步将新版的服务权重提高,以打到服务的灰度发布的目的

需要源码的同学可前往下载:https://download.csdn.net/download/zhangcongyi420/24656803

本篇到此结束,最后感谢观看!

猜你喜欢

转载自blog.csdn.net/zhangcongyi420/article/details/120476289