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