Skip to content

灰度发布

问题

  1. 开发环境,开发人员调试一个功能,都要启动全部项目?能否蹭别人的nacos、gateway、公共服务等,能否只启动自己的业务服务,注册到别人的nacos?
  2. 生产环境, 如何不停机升级?

场景

假设在测试环境,在测试服务器上每个服务启动2个节点,开发人员张三和李四也同时启动服务注册到测试环境的同一个nacos中,此时前端开发人员想要和张三对接biz-server服务的接口,通过nginx访问时,如何精确的访问到张三启动的网关服务和其他服务(biz-server、oauth-server等)?

想要通过nginx精确访问到网关本文暂未实现,请自行研究 (本地、测试环境可以不走nginx,让前端直接访问张三的网关服务)。这里只讨论请求通过任意网关后,如何精确路由到张三的biz-server,且biz-server通过feign调用oauth-server的接口,如何精确调用到张三自己的oauth-server。

  1. 假设 acuity-biz-server 服务存在A接口(/product/list), A接口内部执行自己逻辑后,又调用了acuity-oauth-server 的 test接口

    java
    // acuity-biz-server 服务方法
    private final OauthApi oauthApi;
    @GetMapping("/product/list")
    public R<Object> productList(@RequestParam(required = false) Long id) throws InterruptedException { 
       // 自己意淫一堆逻辑
       return oauthApi.test(id);
    }
    
    // acuity-oauth-server 服务方法
    @GetMapping("/test")
    public R<Object> test(@RequestParam(required = false) Long id) throws InterruptedException { 
    // 自己在意淫一堆逻辑
    return R.success(id + 1);
    }
    // acuity-biz-server 服务方法
    private final OauthApi oauthApi;
    @GetMapping("/product/list")
    public R<Object> productList(@RequestParam(required = false) Long id) throws InterruptedException { 
       // 自己意淫一堆逻辑
       return oauthApi.test(id);
    }
    
    // acuity-oauth-server 服务方法
    @GetMapping("/test")
    public R<Object> test(@RequestParam(required = false) Long id) throws InterruptedException { 
    // 自己在意淫一堆逻辑
    return R.success(id + 1);
    }
  2. 在测试环境的所有服务服务的配置文件bootstrap.yml中配置gray_version: test, 并将每个服务启动2个实例。

yaml
spring:
  cloud:
    nacos:
      discovery:
        metadata:
          gray_version: test  # 测试环境配置为 test
spring:
  cloud:
    nacos:
      discovery:
        metadata:
          gray_version: test  # 测试环境配置为 test
  1. 若张三要调试 业务服务 acuity-biz-server,则需要张三本地将 bootstrap.yml 文件中的 gray_version 改成 zs (任意字符串都行,只要不于其他人员重复即可)

  2. 同理李四要调试业务服务 acuity-biz-server,则需要李四本地将 bootstrap.yml 文件中的 gray_version 改成 ls

  3. 张三和李四同时启动 acuity-biz-server,此时注册到nacos中的acuity-biz-server就存在4个实例,分别是测试环境、张三、李四的

  4. 启动后,可以在nacos中查看每个服务的各个示例的元数据,如图一。

  5. 前端修改 acuity-web-plus/src/utils/http/axios/index.ts 文件中以下配置

    // 可以设置为 zs 或 ls 或 test 
    (config as Recordable).headers['gray_version'] = 'zs';
    // 可以设置为 zs 或 ls 或 test 
    (config as Recordable).headers['gray_version'] = 'zs';

总结:

  1. 前端修改 acuity-web-plus/src/utils/http/axios/index.ts 文件中以下配置

    // 可以设置为 zs 或 ls 或 test 
    (config as Recordable).headers['gray_version'] = 'zs';
    // 可以设置为 zs 或 ls 或 test 
    (config as Recordable).headers['gray_version'] = 'zs';
  2. 后端修改 bootstrap.yml 中的以下配置

    yaml
    spring:
    cloud:
     nacos:
       discovery:
         metadata:
           gray_version: test    # 测试环境配置为 test, 张三本地调试修改为 zs , 李四本地调试修改为 ls
    spring:
    cloud:
     nacos:
       discovery:
         metadata:
           gray_version: test    # 测试环境配置为 test, 张三本地调试修改为 zs , 李四本地调试修改为 ls

源码参考

  1. 网关 路由负载均衡算法: GrayVersionLoadBalancer
  2. feign 调用负载均衡算法: GrayscaleVersionRoundRobinLoadBalancer

原理解析

  1. 请求头或线程上下文中查找 gray_version 参数
  2. 请求头或线程上下文 中 不存在 gray_version 参数,则从已注册到nacos的服务中 轮询 一个服务节点
  3. 请求头或线程上下文 中 存在 gray_version 参数, 则从已注册到nacos的服务中,查找设置了元数据 gray_version ,且元数据 中 gray_version 等于 请求头或线程上下文 中 gray_version 的服务节点。 若 请求头或线程上下文 中的 gray_version 参数和后端所有服务的元数据 gray_version都不匹配,则仍然按 轮询 算法 查找服务节点。

欢迎使用天源云Saas快速开发系统