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 提供的组件即可
参考代码如下
最后更新于