Jenkins + NACOS + GATEWAY 实现微服务不停机部署

2023-10-27

Nacos 版本  

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

Gateway 版本

<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<version>3.1.1</version>
  1. gateway 服务配置

 在Nacos 管理端下线服务后,Nacos服务端有定时延迟机制导致不能及时更新状态,导致服务重启后gateway网关依然会把请求分配到已经下线且停机的服务,导致接口提示未找到服务

此时需要更改gateway服务配置,定制自己的监听事件

增加MySubscribeConfig配置文件

/resources/META-INF 下增加spring.factories配置文件,内容如下:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.daishu.gateway.config.MySubscribeConfig

  
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.NacosServiceManager;
import com.daishu.common.core.utils.SpringContextHolder;
import com.daishu.gateway.config.loadbalancer.MyNacosEventListener;
import com.daishu.gateway.config.loadbalancer.MyNacosSubscribe;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.cloud.loadbalancer.cache.LoadBalancerCacheManager;
import org.springframework.cloud.loadbalancer.config.LoadBalancerCacheAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;


/**
 * 首先订阅当前网关关注的服务
 * nacos服务更新通知,但是gateway有一套自己的服务缓存列表。每次接到通知更新不及时导致转发到已经下线的服务
 * gateway获取缓存参考:org.springframework.cloud.loadbalancer.core.CachingServiceInstanceListSupplier
 * nacos订阅参考:com.alibaba.cloud.nacos.discovery.NacosWatch#start()
 *
 */
@Configuration
@Import(SpringContextHolder.class)
@AutoConfigureAfter(LoadBalancerCacheAutoConfiguration.class)
public class MySubscribeConfig {

    @Bean
    public MyNacosSubscribe getMyNacosSubscribe(NacosServiceManager nacosServiceManager, NacosDiscoveryProperties properties){
        LoadBalancerCacheManager cacheManager = SpringContextHolder.getBean(LoadBalancerCacheManager.class);
        return new MyNacosSubscribe(nacosServiceManager,properties,new MyNacosEventListener(cacheManager));
    }
}


import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.NacosServiceManager;
import com.alibaba.nacos.api.naming.NamingService;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;

import java.util.HashSet;
import java.util.Set;

/**
 * 订阅nacos推送更新事件
 * 启动和加载路由时重新订阅
 */
public class MyNacosSubscribe implements ApplicationRunner {
    private NacosServiceManager nacosServiceManager;
    private NacosDiscoveryProperties properties;
    private MyNacosEventListener myEventListener;

    private Set<String> getRouteServices(){
        //  这里返回自己要订阅的服务名称
        Set<String> serviceName=new HashSet<>();
        serviceName.add("server-name");
        return serviceName;
    }
    // 这里监听时间是为了在路由信息修改时候,重新订阅服务的。如果说路由重新加载不会有订阅变动的话,可以去掉
    @org.springframework.context.event.EventListener({RefreshRoutesEvent.class})
    public void subscribe() {
        NamingService namingService = nacosServiceManager
                .getNamingService(properties.getNacosProperties());
        try {
            Set<String> services = getRouteServices();
            if(CollectionUtil.isNotEmpty(services)){
                for (String service : services) {
                    namingService.subscribe(service, properties.getGroup(),
                            null, myEventListener);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run(ApplicationArguments args) throws Exception {
        subscribe();
    }

    public MyNacosSubscribe(NacosServiceManager nacosServiceManager, NacosDiscoveryProperties properties, MyNacosEventListener myEventListener) {
        this.nacosServiceManager = nacosServiceManager;
        this.properties = properties;
        this.myEventListener = myEventListener;
    }


import com.alibaba.cloud.nacos.discovery.NacosServiceDiscovery;
import com.alibaba.nacos.api.naming.listener.Event;
import com.alibaba.nacos.api.naming.listener.EventListener;
import com.alibaba.nacos.api.naming.listener.NamingEvent;
import com.alibaba.nacos.api.naming.pojo.Instance;
import org.springframework.cache.Cache;
import org.springframework.cloud.loadbalancer.cache.LoadBalancerCacheManager;
import org.springframework.cloud.loadbalancer.core.CachingServiceInstanceListSupplier;

import java.util.List;

/**
 * 处理nacos推送更新事件
 */
public class MyNacosEventListener implements EventListener {

    private LoadBalancerCacheManager loadBalancerCacheManager;
    @Override
    public void onEvent(Event event) {
        try {
            if (event instanceof NamingEvent) {
                Cache cache = loadBalancerCacheManager.getCache(CachingServiceInstanceListSupplier.SERVICE_INSTANCE_CACHE_NAME);
                if(cache!=null){
                    NamingEvent namingEvent = ((NamingEvent) event);
                    String serviceName = namingEvent.getServiceName();
                    List<Instance> instances = namingEvent.getInstances();
                    cache.put(serviceName,  NacosServiceDiscovery.hostToServiceInstanceList(instances,serviceName));
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public MyNacosEventListener(LoadBalancerCacheManager loadBalancerCacheManager) {
        this.loadBalancerCacheManager = loadBalancerCacheManager;
    }
}

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Lazy;

/**
 * spring工具类
 */
@Slf4j
@Lazy(false)
public class SpringContextHolder implements ApplicationContextAware, DisposableBean {

    private static ApplicationContext applicationContext = null;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        SpringContextHolder.applicationContext = applicationContext;
    }

    public static <T> T getBean(Class<T> requiredType) {
        return applicationContext.getBean(requiredType);
    }

    public static void clearHolder() {
        if (log.isDebugEnabled()) {
            log.debug("清除SpringContextHolder中的ApplicationContext:" + applicationContext);
        }
        applicationContext = null;
    }


    @Override
    public void destroy() {
        SpringContextHolder.clearHolder();
    }


}

配置好重启网关服务,naocs管理端修改服务下线状态,发现断点已经进入监听类即完成配置

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Jenkins + NACOS + GATEWAY 实现微服务不停机部署 的相关文章

随机推荐

  • DAC芯片CBM128S085

    一 硬件介绍 1 1 芯片内部框架图 1 2 CBM12S085引脚定义 引脚介绍 DAC SYNC 电平触发控制输入 低电平有效 SCLK 时钟输入 DAC DIN 串行数据输入 VOUTA H则是对应的8个电压模拟输出通道 二 软件实现
  • 找出数组中每个数的右边第一个比它大的数

    vector
  • 人工智能 猴子摘香蕉问题

    1 定义描述环境状态的谓词 AT x w x在w处 个体域 x monkey w a b c box HOLD x t x手中拿着t 个体域 t box banana EMPTY x x手中是空的 ON t y t在y处 个体域 y b c
  • 三角形

    1 2 3 4 5 6
  • function 与 => 的区别

    function 与 的区别主要是他们的作用域的不同 在JS中 箭头函数并不是简单的function 匿名函数的简写语法糖 实际上 箭头函数和匿名函数有个明显的区别 gt 箭头函数内部的this是词法作用域 在编写函数时就已经确定了 fun
  • CentOS8.4安装Redis6.2.6

    一 下载 官网 Redis 我们下载 Stable 稳定版 cd mydata wget https download redis io releases redis 6 2 6 tar gz 二 安装redis6 2 6 1 安装到 us
  • python编一函数s(x) 求级数和_Python 编程基础之高阶函数篇(一)

    高阶函数 能接受函数作为参数的函数 如 f abs def add x y f return f x f y 如果我们用 add 5 9 f 来调用该高阶函数 则返回结果为 14 abs是Python提供的求绝对值的函数 Python中的m
  • Django实现音乐网站 ⒅

    使用Python Django框架做一个音乐网站 本篇主要为歌单列表 歌单详情及推荐页 歌单内容改动 目录 歌单列表 设置路由 视图处理 模板渲染 歌单 单曲列表 设置路由 视图处理 模板渲染 推荐页 歌单列表 模板渲染修改 总结 歌单列表
  • C语言字节数

    bool 1字节 char 1字节 short 2字节 string 4字节 int 4字节 指针4字节 float 4字节 double 8字节 long 4或8字节 long long 8字节 long double 12字节 空类1字
  • ArcFace loss与其他改进loss对比

    ArcFace loss与其他改进loss对比 sphereFace A softmax cos ma 角度距离 cosFace AM softmax cosa m 余弦距离 ArcFace Arc softmax cos a m 角度距离
  • ICCV, ECCV, CVPR,IEEE的关系

    计算机视觉领域世界三大顶级会议分别为CVPR ICCV和ECCV CVPR CVPR 英文全称IEEE Conference on Computer Vision and Pattern Recognition 中文全称是国际计算机视觉与模
  • FeignClient中name和url属性的作用

    定义 feign是声明式的web service客户端 它让微服务之间的调用变得更简单了 类似controller调用service Spring Cloud集成了Ribbon和Eureka 可在使用Feign时提供负载均衡的http客户端
  • node-ffi ffi.Library往电脑窗口的任意光标处输入内容(user32.dll)window电脑

    node ffi ffi Library往电脑窗口的任意光标处输入内容 user32 dll window电脑 类似键盘输入法的效果 前提 遇到问题 解决问题了 补充安装库遇到的问题 类似键盘输入法的效果 我node项目和electron项
  • 语义分割评价指标mIOU的计算

    语义分割评价指标mIOU的计算 注意事项 这是针对重构了的语义分割网络 而不是之前的那个 所以不要询问原来的网络计算miou要怎么做 因为整个文件构架差距过大 建议使用新构架 学习前言 算一下语义分割的miou 做好生态链 什么是mIOU
  • 北大青鸟汉字注释机内码_北大青鸟消防主机如何编写汉字注释?

    北大青鸟消防主机汉字注释有两种 一种是利用编程调试软件进行编写文字注释 另一种是直接在消防主机上对照汉字机内码 进入系统进行编辑 下面小编跟大家介绍的是使用编程调试软件进行文字注释的方法 1 序号 项 序号 项自动生成 不需用户自己填写 2
  • 【SSO单点登录】JWT续签问题 && OAuth2.0 中的refreshToken刷新机制

    本篇速览 JWT续签问题 快过期时返回新的token refreshToken 如何判断refreshToken的有效性 扩展 OAuth2 0 中的refreshToken刷新机制 其他需要刷新token的情况 用户修改了角色权限 删除了
  • SQL优化之 not in

    not in select from dic region old a where a region code not in select b region code from dic region b PL SQL 执行 选择17 行 耗
  • 通过liquibase将PostgreSQL数据库导入到H2数据库

    1 背景 项目中使用的数据库是PostgreSQL 在做测试时 想使用H2代替 2 问题 2 1 保留字 在PostgreSQL中使用了几个H2的保留字 例如 end offset foreign 这些保留字是不能作为表的字段名 2 2 字
  • Java加解密的基础

    在Java的安全包中 包括了三部分内容 1 JCA JCE Java Cryptography Architecture JavaCryptography Extensions 2 JSSE Java Secure Sockets Exte
  • Jenkins + NACOS + GATEWAY 实现微服务不停机部署

    Nacos 版本