1、布景

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

此种完成办法是我自己记载下,目前未在出产环境中使用,此处记载是为了今后遇到此种场景,能够找到一种处理方案

2、处理方案

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

Spring Cloud Alibaba实现服务的无损下线功能
经过一顿Debug之后,从上图中可知,咱们获取到可用的服务实例信息,会从缓存中获取,那么如果当服务下线后,咱们清空这个服务的缓存的信息,那么下次在获取这个服务的信息就是最新的了,那么问题就处理了。

2.2 处理思路

Spring Cloud Alibaba实现服务的无损下线功能

  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
@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、注解收效参阅文档

github.com/nacos-group… github.com/alibaba/spr…

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将会回来provideripport信息。
2、http://localhost:9003/shutdown 将会将自己从nacos server下线,而且操作 nacos config,改变装备文件的内容。
3、gatewayconsumer监听到装备改变,更新服务的缓存,从而下次访问,不会访问到这个下线的服务。

4.2 演示

Spring Cloud Alibaba实现服务的无损下线功能

5、完整代码

gitee.com/huan1993/sp…

6、参阅链接

1、github.com/nacos-group… 2、github.com/alibaba/spr…