Spring Cloud Alibaba实现服务的无损下线功能(案例讲解)
作者:huan1993的技术分享 发布时间:2022-07-05 08:14:25
1、背景
最近用到了Spring Cloud Alibaba
开发微服务,在开发的过程中发现,当我们的服务上线
或下线
的时候,我们的Spring Cloud Gateway
需要一段时间才能感知到,那么有没有办法能够让服务立即感知到呢?答案是可以的
。
此种实现方式是我自己记录下,目前未在生产环境中使用,此处记录是为了以后遇到此种场景,可以找到一种解决方案
2、解决方案
2.1 找到通过负载均衡组件获取可用服务信息的地方
通过一顿Debug
之后,从上图中可知,我们获取到可用的服务实例信息,会从缓存中获取
,那么如果当服务下线后,我们清空这个服务的缓存的信息,那么下次在获取这个服务的信息就是最新的了,那么问题就解决了。
2.2 解决思路
服务提供方或消费方,同时监听
Spring Cloud Config
中的某个配置文件,比如lossless
文件服务下线时, 第一步: 从
nacos
上将自身这个实例下线。 第二步: 通过api
更新lossless
文件中的内容,记录服务下线的服务名加上时间戳
。消费者或网关,监听到
lossless
配置文件的变更,获取到服务名
,然后将这个服务名对应的缓存清空
。
3、部分实现代码
3.1 引入jar
<dependencies>
<!-- 服务发现 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- nacos 配置 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- 引入这个是为了使 @NacosConfigListener 注解生效 -->
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-spring-context</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- 负载均衡组件 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<!-- 使bootstrap.yaml中的配置生效 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
3.2 编写服务下线方法
@Component
@Slf4j
public class LosslessOfflineApi {
@Resource
private NacosConfigManager nacosConfigManager;
@Resource
private NacosServiceManager nacosServiceManager;
@Resource
private NacosDiscoveryProperties nacosDiscoveryProperties;
/**
* 服务下线
*
* @throws NacosException NacosException
*/
public void offlineService() throws NacosException {
log.info("触发服务下线 serviceName:[{}]", nacosDiscoveryProperties.getService());
nacosServiceManager.nacosServiceShutDown();
nacosConfigManager.getConfigService()
.publishConfig(NacosConstant.DATA_ID, NacosConstant.GROUP,
nacosDiscoveryProperties.getService() + NacosConstant.SPLIT + System.currentTimeMillis());
}
}
此处需要注意的是: 使用nacosConfigManager.getConfigService().publishConfig
发布配置,此处更新配置中的 服务名+时间戳
,如果只是更新服务名,则可能不会触发监听事件。
3.3 监听配置变更,清除服务缓存
3.3.1 使@NacosConfigListener注解生效
1、引入配置
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-spring-context</artifactId>
<version>1.1.1</version>
</dependency>
2、开启注解
@Configuration
@EnableNacos(globalProperties =
@NacosProperties(serverAddr = "${spring.cloud.nacos.config.server-addr}")
)
public class NacosConfiguration {
}
3、注解生效参考文档
https://github.com/nacos-group/nacos-spring-project
https://github.com/alibaba/spring-cloud-alibaba/issues/458
3.3.2 监听配置、清除缓存
@Component
@RequiredArgsConstructor
@Slf4j
public class ListenerConfigChange {
@Resource
private DefaultLoadBalancerCacheManager defaultLoadBalancerCacheManager;
@Resource
private NacosServiceManager nacosServiceManager;
@Resource
private NacosDiscoveryProperties nacosDiscoveryProperties;
@Resource
private NacosServiceDiscovery nacosServiceDiscovery;
@Resource
private NacosConfigManager nacosConfigManager;
@NacosConfigListener(groupId = GROUP, dataId = DATA_ID)
public void configChange(String config) {
log.warn("==>接收到 无损服务下线 配置变更:[{}]", config);
String serviceName = config.split(SPLIT)[0];
log.info("需要无损下线的服务名:[{}]", serviceName);
Cache cache = defaultLoadBalancerCacheManager.getCache(SERVICE_INSTANCE_CACHE_NAME);
if (null != cache) {
cache.evict(serviceName);
log.info("失效serviceName:[{}]的缓存", serviceName);
}
}
}
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
将会返回provider
的ip
和port
信息。
2、http://localhost:9003/shutdown
将会将自己从nacos server下线,并且操作 nacos config,变更配置文件的内容。
3、gateway
和consumer
监听到配置变更,更新服务的缓存,从而下次访问,不会访问到这个下线的服务。
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


猜你喜欢
- bean的定义继承bean定义可以包含很多的配置信息,包括构造函数的参数,属性值,比如初始化方法,静态工厂方法名等容器的具体信息。子bean
- 使用的场景常常遇到一些项目中多环境切换的问题。比如在开发过程中用到开发环境,在测试中使用测试环境,在生产中用生产环境的情况。springbo
- 一,项目简介项目编号:BS-SC-029本系统主要为种值水果和农户和水果经销商搭建一个B2B的电子商务平台,系统共包含三个角色:农户、经销商
- 破解流程破解Android程序流程:反编译—>分析–>修改–>回编译–>签名,这些都是在命令行中操作,当然也有集成了
- Android的消息机制几乎是面试必问的话题,当然也并不是因为面试,而去学习,更重要的是它在Android的开发中是必不可少的,占着举足轻重
- Notification的作用通知(Notification)是Android系统中比较有特色的一个功能。当某个应用程序希望向用户发出一些提
- 1. 确保你项目能编译通过,安装java jdk 环境填写环境变量2. 添加SpringBootServletInitializer的子类重
- 总结:对应某个类的实例化的对象tc, 遍历获取所有属性(子成员)的方法(采用反射):Type t = tc.GetType();//获得该类
- 本功能是在winform平台上实现的,其他平台大同小异,不多做介绍。1.首先创建一个测试用winform窗体2.在winform窗体上添加一
- 1.简述描述:1、对输入的字符串进行加解密,并输出。2、加密方法为:当内容是英文字母时则用该英文字母的后一个字母替换,同时字母变换大小写,如
- File 类:文件和目录路径名的抽象表示。注意:File 类只能操作文件的属性,文件的内容是不能操作的。1、File 类的字段我们知道,各个
- 本文实例讲述了Java实现特定范围的完数输出算法。分享给大家供大家参考,具体如下:题目内容:一个正整数的因子是所有可以整除它的正整数。而一个
- Java实现基于Socket的简单通信 一.ServerSocket1.使用JavaFX写的小界面,方便观察客户端连接情况 &nb
- ViewAndroid所有的控件都是View或者View的子类,它其实表示的就是屏幕上的一块矩形区域,用一个Rect来表示,left,top
- 本文实例讲述了C#实现的MD5加密功能与用法。分享给大家供大家参考,具体如下:1、创建MD5Str.cs加密处理类public class
- 最近有小伙伴问我mybatis有没有自动创建表结构的功能,因为他们之前一直使用hibernate用习惯了,理所当然的认为,在实体类上配置 *
- 如何快速判断一个元素是不是在一个集合里?这个题目是我最近面试的时候常问的一个问题,这个问题不同人都有很多不同的回答。今天想介绍一个很少有人会
- Dialog和Toast所有人肯定都不会陌生的,这个我们平时用的实在是太多了。而Snackbar是Design Support库中提供的新控
- spring注解配置实现事务控制1、导入相关依赖这个项目当中使用了spring的JdbcTemplate模板类来用在控制层简化jdbc代码,
- 首先是.select在MP查询中,默认查询所有的字段,如果有需要也可以通过select方法进行指定字段。其中要注意的细节:wrapper.s