经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Spring » 查看文章
Spring Cloud Alibaba实现服务的无损下线功能
来源:cnblogs  作者:huan1993  时间:2023/3/14 8:48:34  对本文有异议

1、背景

最近用到了Spring Cloud Alibaba开发微服务,在开发的过程中发现,当我们的服务上线下线的时候,我们的Spring Cloud Gateway需要一段时间才能感知到,那么有没有办法能够让服务立即感知到呢?答案是可以的

此种实现方式是我自己记录下,目前未在生产环境中使用,此处记录是为了以后遇到此种场景,可以找到一种解决方案

2、解决方案

2.1 找到通过负载均衡组件获取可用服务信息的地方

获取到一个可用的服务实例
通过一顿Debug之后,从上图中可知,我们获取到可用的服务实例信息,会从缓存中获取,那么如果当服务下线后,我们清空这个服务的缓存的信息,那么下次在获取这个服务的信息就是最新的了,那么问题就解决了。

2.2 解决思路

服务下线时序图

  1. 服务提供方或消费方,同时监听 Spring Cloud Config中的某个配置文件,比如lossless文件
  2. 服务下线时, 第一步:nacos上将自身这个实例下线。 第二步: 通过api更新lossless 文件中的内容,记录服务下线的服务名加上时间戳
  3. 消费者或网关,监听到lossless配置文件的变更,获取到服务名,然后将这个服务名对应的缓存清空

3、部分实现代码

3.1 引入jar

  1. <dependencies>
  2. <!-- 服务发现 -->
  3. <dependency>
  4. <groupId>com.alibaba.cloud</groupId>
  5. <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  6. </dependency>
  7. <!-- nacos 配置 -->
  8. <dependency>
  9. <groupId>com.alibaba.cloud</groupId>
  10. <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
  11. </dependency>
  12. <!-- 引入这个是为了使 @NacosConfigListener 注解生效 -->
  13. <dependency>
  14. <groupId>com.alibaba.nacos</groupId>
  15. <artifactId>nacos-spring-context</artifactId>
  16. <version>1.1.1</version>
  17. </dependency>
  18. <dependency>
  19. <groupId>org.projectlombok</groupId>
  20. <artifactId>lombok</artifactId>
  21. </dependency>
  22. <!-- 负载均衡组件 -->
  23. <dependency>
  24. <groupId>org.springframework.cloud</groupId>
  25. <artifactId>spring-cloud-starter-loadbalancer</artifactId>
  26. </dependency>
  27. <!-- 使bootstrap.yaml中的配置生效 -->
  28. <dependency>
  29. <groupId>org.springframework.cloud</groupId>
  30. <artifactId>spring-cloud-starter-bootstrap</artifactId>
  31. </dependency>
  32. <dependency>
  33. <groupId>org.springframework.boot</groupId>
  34. <artifactId>spring-boot-starter-web</artifactId>
  35. </dependency>
  36. </dependencies>

3.2 编写服务下线方法

  1. @Component
  2. @Slf4j
  3. public class LosslessOfflineApi {
  4. @Resource
  5. private NacosConfigManager nacosConfigManager;
  6. @Resource
  7. private NacosServiceManager nacosServiceManager;
  8. @Resource
  9. private NacosDiscoveryProperties nacosDiscoveryProperties;
  10. /**
  11. * 服务下线
  12. *
  13. * @throws NacosException NacosException
  14. */
  15. public void offlineService() throws NacosException {
  16. log.info("触发服务下线 serviceName:[{}]", nacosDiscoveryProperties.getService());
  17. nacosServiceManager.nacosServiceShutDown();
  18. nacosConfigManager.getConfigService()
  19. .publishConfig(NacosConstant.DATA_ID, NacosConstant.GROUP,
  20. nacosDiscoveryProperties.getService() + NacosConstant.SPLIT + System.currentTimeMillis());
  21. }
  22. }

此处需要注意的是: 使用nacosConfigManager.getConfigService().publishConfig 发布配置,此处更新配置中的 服务名+时间戳,如果只是更新服务名,则可能不会触发监听事件。

3.3 监听配置变更,清除服务缓存

3.3.1 使@NacosConfigListener注解生效

1、引入配置

  1. <dependency>
  2. <groupId>com.alibaba.nacos</groupId>
  3. <artifactId>nacos-spring-context</artifactId>
  4. <version>1.1.1</version>
  5. </dependency>

2、开启注解

  1. @Configuration
  2. @EnableNacos(globalProperties =
  3. @NacosProperties(serverAddr = "${spring.cloud.nacos.config.server-addr}")
  4. )
  5. public class NacosConfiguration {
  6. }

3、注解生效参考文档

https://github.com/nacos-group/nacos-spring-project
https://github.com/alibaba/spring-cloud-alibaba/issues/458

3.3.2 监听配置、清除缓存

  1. @Component
  2. @RequiredArgsConstructor
  3. @Slf4j
  4. public class ListenerConfigChange {
  5. @Resource
  6. private DefaultLoadBalancerCacheManager defaultLoadBalancerCacheManager;
  7. @Resource
  8. private NacosServiceManager nacosServiceManager;
  9. @Resource
  10. private NacosDiscoveryProperties nacosDiscoveryProperties;
  11. @Resource
  12. private NacosServiceDiscovery nacosServiceDiscovery;
  13. @Resource
  14. private NacosConfigManager nacosConfigManager;
  15. @NacosConfigListener(groupId = GROUP, dataId = DATA_ID)
  16. public void configChange(String config) {
  17. log.warn("==>接收到 无损服务下线 配置变更:[{}]", config);
  18. String serviceName = config.split(SPLIT)[0];
  19. log.info("需要无损下线的服务名:[{}]", serviceName);
  20. Cache cache = defaultLoadBalancerCacheManager.getCache(SERVICE_INSTANCE_CACHE_NAME);
  21. if (null != cache) {
  22. cache.evict(serviceName);
  23. log.info("失效serviceName:[{}]的缓存", serviceName);
  24. }
  25. }
  26. }

4、实现

4.1 服务准备

服务 端口 提供api 备注
nacos-lossless-gateway 9001 /consumer/** 路由到consumer服务
nacos-feign-consumer 9002 /fetchProviderServerInfo 通过feign接口,获取provider服务的ip和port
nacos-provider-9003 9003 /shutdown 从nacos server上下线服务,发布配置变更
nacos-provider-9004 9004 /shutdown 从nacos server上下线服务,发布配置变更

解释:
1、通过gateway访问 http://localhost:9001/consumer/fetchProviderServerInfo将会返回provideripport信息。
2、http://localhost:9003/shutdown 将会将自己从nacos server下线,并且操作 nacos config,变更配置文件的内容。
3、gatewayconsumer监听到配置变更,更新服务的缓存,从而下次访问,不会访问到这个下线的服务。

4.2 演示

演示

5、完整代码

https://gitee.com/huan1993/spring-cloud-alibaba-parent/tree/master/nacos-lossless-offline

6、参考链接

1、https://github.com/nacos-group/nacos-spring-project
2、https://github.com/alibaba/spring-cloud-alibaba/issues/458

原文链接:https://www.cnblogs.com/huan1993/p/17204685.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号