spring cloud手动下掉节点

spring cloud手动下掉节点

背景

项目中使用nacos作为注册中心,在服务发布过程中,经常会遇到服务发布过程中实例重启过程中还会有流量打向实例A,对业务造成一定影响

目标

实现服务的平滑重启

方案

现状介绍

当前服务是部署在虚拟机上的,在服务重启时,使用systemctl命令实现服务重启

systemctl restart xxxx

重启过程中,会先向服务发送SIGTERM(15)信号,然后等待一段时间之后再发送SIGKILL(9)

SIGTERM信号java程序可以通过Runtime类监听,在程序结束之前做一些善后工作

Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            try {
                doSomeThing();
            } catch (Exception ex) {
                log.error("doSomeThing error. ", ex);
            }

        }));

事实上spring已经有这部分工作,参考

org.springframework.boot.SpringApplicationShutdownHook

spring cloud注册中心实现

参考org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration#destroy

通过监听spring WebServerInitializedEvent实现服务的注册,见onApplicationEvent;通过bean销毁钩子实现服务的下线,参考destroy方法,方法上有@PreDestroy注解,会在bean被销毁前调用。

nacos实现了该类,参考com.alibaba.cloud.nacos.registry.NacosServiceRegistry;也就是说nacos会在服务销毁之前将当前实例从nacos上下掉

为什么重启过车中还会有流量?

服务销毁前,已经从上有打过来的未处理完的流量

当前spring boot 已经配置了平滑销毁,具体配置如下

理论上销毁前会将未处理完的请求处理完之后再销毁服务,所以这种可能排除

服务从nacos上下掉之后,上游本地的缓存还未更新,导致上游未及时感知到下游提供方的变更

nacos discover client实现参考com.alibaba.cloud.nacos.discovery.NacosDiscoveryClient

接下来看com.alibaba.cloud.nacos.discovery.NacosServiceDiscovery

再看com.alibaba.nacos.client.naming.NacosNamingService

再看com.alibaba.nacos.client.naming.core.HostReactor

从这里可以看到,调用方的提供方实例列表是异步更新的,有一定的时间差,一次存在这种可能。

解决

如上分析,流量基本上是因为nacos客户端更新缓存延迟造成的,如果要解决的,可以提前从nacos上下掉要重启的实例,等待一段时间后再重启

因此,可以在应用上提供一个自动下线服务的接口,在发布之前curl一下,等待一段时间后再重启应用

自动下线服务业很简单,直接利用spring cloud 提供的组件即可

参考代码如下

最后更新于