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

<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@Slf4jpublic 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@Slf4jpublic 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-gateway9001/consumer/**路由到consumer服务
nacos-feign-consumer9002/fetchProviderServerInfo通过feign接口,获取provider服务的ip和port
nacos-provider-90039003/shutdown从nacos server高低线服务,公布配置变更
nacos-provider-90049004/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