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
@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将会返回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

Spring Cloud Alibaba实现服务的无损下线功能的更多相关文章

  1. Spring Cloud Alibaba Nacos 服务注册与发现功能实现!

    Nacos 是 Spring Cloud Alibaba 中一个重要的组成部分,它提供了两个重要的功能:服务注册与发现和统一的配置中心功能. 服务注册与发现功能解决了微服务集群中,调用者和服务提供者连 ...

  2. Spring Cloud Alibaba | Nacos服务注册与发现

    目录 Spring Cloud Alibaba | Nacos服务注册与发现 1. 服务提供者 1.1 pom.xml项目依赖 1.2 配置文件application.yml 1.3 启动类Produ ...

  3. Spring Cloud Alibaba | Sentinel: 服务限流基础篇

    目录 Spring Cloud Alibaba | Sentinel: 服务限流基础篇 1. 简介 2. 定义资源 2.1 主流框架的默认适配 2.2 抛出异常的方式定义资源 2.3 返回布尔值方式定 ...

  4. Spring Cloud Alibaba | Sentinel: 服务限流高级篇

    目录 Spring Cloud Alibaba | Sentinel: 服务限流高级篇 1. 熔断降级 1.1 降级策略 2. 热点参数限流 2.1 项目依赖 2.2 热点参数规则 3. 系统自适应限 ...

  5. Spring Cloud Alibaba | 微服务分布式事务之Seata

    Spring Cloud Alibaba | 微服务分布式事务之Seata 本篇实战所使用Spring有关版本: SpringBoot:2.1.7.RELEASE Spring Cloud:Green ...

  6. Spring Cloud Alibaba 的服务注册与发现

    Spring Cloud Alibaba 服务发现例子 一.需求 1.提供者完成的功能 2.消费者完成的功能 3.可以附加的额外配置 二.实现步骤 1.总的依赖引入 2.服务提供者和发现者,引入服务发 ...

  7. Spring Cloud Alibaba微服务生态的基础实践

    目录 一.背景 二.初识Spring Cloud Alibaba 三.Nacos的基础实践 3.1 安装Nacos并启动服务 3.2 建立微服务并向Nacos注册服务 3.3 建立微服务消费者进行服务 ...

  8. Spring Cloud Alibaba微服务一站式解决方案-开篇v2.2.1.RELEASE

    学习路线 **本人博客网站 **IT小神 www.itxiaoshen.com 生态概述 架构演进 什么是微服务 https://martinfowler.com/microservices/ Mic ...

  9. Spring Cloud Alibaba微服务架构入门最容易理解篇

    微服务架构介绍 Spring Cloud Alibaba推荐的微服务生态架构基于分层架构实现如下: 接入层:最外层为LVS+Keepalived,可承受几十万级高并发流量洪峰,然后再通过内层的ngin ...

  10. 4.【Spring Cloud Alibaba】服务容错-sentinel

    雪崩效应 常见容错方案 超时 限流 仓壁模式 断路器模式 断路器三态转换 使用Sentinel实现容错 什么是Sentinel https://github.com/alibaba/Sentinel ...

随机推荐

  1. C/C++ 关键字 static 详细解析

    static关键字是一个修饰符,根const类似,被它修饰的变量和函数分别被称为静态变量和静态函数,根据修饰的对象的不同,static表现出来的作用也不同. 1. C语言中的 static 在C语言中 ...

  2. 一、Java简单概述

    一 . Java组成部分 JDK : java development kit (Java开发工具) JDK是提供给Java开发人员使用的,其中包含了java的开发工具,也 包括了JRE. 所以安装了 ...

  3. IDEA+SpringBoot整合Swagger2创建API文档

    ------------恢复内容开始------------ 1.创建SpringBoot项目 2.选择快捷方式创建springboot项目 3.工程文件树形图 4.pom.xml中导入Swagger ...

  4. 启动appium服务时报错,服务不通:Original error: Could not find 'apksigner.jar'

    启动时报错,服务不通:Original error: Could not find 'apksigner.jar' 是因为少了个文件,添加个文件就好了,可以参考下面的帖子. 可以参考这个帖子:http ...

  5. java mybatisplus+springboot服务器跨域问题

    项目本地增删改测试正常,上传到  阿里服  页面出现了 跨域报错问题! 解决方案:添加一个过滤器 package com.rl;import org.springframework.stereotyp ...

  6. vue后台管理系统——订单管理模块

    电商后台管理系统的功能--订单管理模块 1. 订单管理概述 订单管理模块用于维护商品的订单信息, 可以查看订单的商品信息.物流信息,并且可以根据实际的运营情况对订单做适当的调整. 2. 订单列表 在c ...

  7. 【python基础笔记-3】decimal模块解决浮点数计算精度问题

    通过Decimal('123.456')对象实例化后做 + - * / 等运算符操作计算结果不会出现精度问题. Tips:值得注意的2点是 1.Decimal接收的入参是str,所以如果原本操作的数据 ...

  8. 为什么javac后加.java,java后不加.class?

    Javac和java命令的用法:javac需要文件,Java需要执行类或jar文件javac用法: java用法 例子 Java命令后的"test.Test.class"会被认为是 ...

  9. vue3 ts vite

    npm init vite@latest npm install -D sassnpm i vantnpm i vite-plugin-style-import@1.4.1 -Dvite.config ...

  10. 对volatile修饰的变量使用memset函数

    背景 今天面试了一家公司,面试官问了我一个开放性的问题.大致意思是,为什么对volatile修饰的变量调用memset函数,编译的时候会报错.当然,我是不知道为什么啦.之前没有遇到过嘛.不过我还是做了 ...