Appearance
灰度发布
问题
- 开发环境,开发人员调试一个功能,都要启动全部项目?能否蹭别人的nacos、gateway、公共服务等,能否只启动自己的业务服务,注册到别人的nacos?
- 生产环境, 如何不停机升级?
场景
假设在测试环境,在测试服务器上每个服务启动2个节点,开发人员张三和李四也同时启动服务注册到测试环境的同一个nacos中,此时前端开发人员想要和张三对接biz-server服务的接口,通过nginx访问时,如何精确的访问到张三启动的网关服务和其他服务(biz-server、oauth-server等)?
想要通过nginx精确访问到网关本文暂未实现,请自行研究 (本地、测试环境可以不走nginx,让前端直接访问张三的网关服务)。这里只讨论请求通过任意网关后,如何精确路由到张三的biz-server,且biz-server通过feign调用oauth-server的接口,如何精确调用到张三自己的oauth-server。
假设 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); }
在测试环境的所有服务服务的配置文件
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
若张三要调试 业务服务 acuity-biz-server,则需要张三本地将
bootstrap.yml
文件中的 gray_version 改成zs
(任意字符串都行,只要不于其他人员重复即可)同理李四要调试业务服务 acuity-biz-server,则需要李四本地将
bootstrap.yml
文件中的 gray_version 改成ls
张三和李四同时启动 acuity-biz-server,此时注册到nacos中的acuity-biz-server就存在4个实例,分别是测试环境、张三、李四的
启动后,可以在nacos中查看每个服务的各个示例的元数据,如图一。
前端修改 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';
总结:
前端修改 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';
后端修改
bootstrap.yml
中的以下配置yamlspring: cloud: nacos: discovery: metadata: gray_version: test # 测试环境配置为 test, 张三本地调试修改为 zs , 李四本地调试修改为 ls
spring: cloud: nacos: discovery: metadata: gray_version: test # 测试环境配置为 test, 张三本地调试修改为 zs , 李四本地调试修改为 ls
源码参考
- 网关 路由负载均衡算法: GrayVersionLoadBalancer
- feign 调用负载均衡算法: GrayscaleVersionRoundRobinLoadBalancer
原理解析
- 从
请求头或线程上下文
中查找 gray_version 参数 - 若
请求头或线程上下文
中 不存在 gray_version 参数,则从已注册到nacos的服务中 轮询 一个服务节点 - 若
请求头或线程上下文
中 存在 gray_version 参数, 则从已注册到nacos的服务中,查找设置了元数据
gray_version ,且元数据
中 gray_version 等于请求头或线程上下文
中 gray_version 的服务节点。 若请求头或线程上下文
中的 gray_version 参数和后端所有服务的元数据
gray_version都不匹配,则仍然按 轮询 算法 查找服务节点。