SpringCloud应用无损下线实践
1、应用无实践背景
现在java主流的损下微服务技术栈毫无疑问是SpringCloud,这也是线实经销商技术部微服务实践采用的技术栈。注册中心采用公司技术部的应用无nacos。在SpringCloud实践中大家普遍遇到的损下问题是应用默认是无法做到无损下线的,需要更多的线实辅助措施才能得到无损下线的效果,本文主要分享我们团队解决应用无损下线的应用无一些实践。
2、损下有损下线
有损下线指的线实是应用在下线过程中,部分请求没有被妥善处理,应用无出现请求异常进而影响应用可用性,损下影响用户使用。线实有损下线原因分析:
损失原因1:springboot实例默认接收到停止信号TERM时,应用无马上停止服务。损下如下图

当springboot实例收到TERM信号立即关闭的线实时候,很有可能请求队列中还有请求,还有一部分正在处理的请求。如果立即关闭这些请求都会损失掉。亿华云计算
解决方案:在springboot 2.3版本以上,提供了优雅关闭(Graceful Shutdown)配置。如下:
server:
shutdown: graceful配置了优雅关闭后,实例关闭过程如下图所示:

springboot实例在收到TERM信号后,不会立即关闭应用,而是进入优雅处理阶段,这个优雅时间段时长可以配置,默认为30秒。
springboot在网络层拒绝新的请求进入的同时,会等队列中的请求和正在处理请求都处理完成或者优雅时间耗尽才关闭应用。这样只要给应用配置合适的优雅关闭阶段时长就可以避免这类请求损失。
损失原因2:在使用注册中心的默认情况下,服务下线状态无法实时通知给调用方。
在微服务引入注册中心的场景下,provider(服务提供方),registry(注册中心),consumer(服务调用方)正常服务调用过程如下:

服务下线时的时序图如下:

当provider收到TERM信号进入Graceful shutdown阶段的时候也就是图中的1时间点,provider在网络层便不再接收新的请求,然后直到时间点4,consumer才停止向provider发送请求。所以损失时间 = 时间点4 – 时间点1。免费源码下载
3、解决方案
方案1:provider下线尽快通知到consumer。Ribbon默认采用轮询拉取服务列表的方式,时间间隔默认为30秒,也就是说
时间点3 – 时间点2 = 30秒 (最长)
对一个服务来说,如果30秒不可用,情况是相当糟糕的,改进方法有两个,一是缩短轮询间隔到5秒左右;二是可以实现注册中心事件推送方式通知consumer更新服务列表,尽量缩短损失时长。但是这只能治标不治本,因为虽然损失时长缩短了,但是仍然还有几秒损失,每次上线都需要损失请求仍然是不可接受的。
方案2:在provider关闭前通知到consumer下线。如果是可以人工干预下线过程,我们大概会这么干:首先把要下线的provider实例从负载中摘除掉确保不再有流量打到下线实例后,才真正执行下线命令。这样就不会有任何流量损失了。只需要将这个流程自动化就可以完美解决了。
好在k8s提供了preStop配置,香港云服务器在k8s平台中,preStop和TERM信号关系是这样的:preStop会先执行完,然后k8s才会给pod发送TERM信号,k8s会给pod的停止设置一个宽限时长,超过宽限时长会强杀掉,这个宽限时长从preStop调用开始计时。采用这个方案的话,服务下线时序图如下:

可以看到当consumer不再往provider打流量后,provider才开始执行shutdown,这样不会有任何损失。
4、实现步骤
1) 缩短轮询间隔在springboot应用中增加如下配置:
ribbon:
ServerListRefreshInterval: 5000 # 服务列表刷新间隔2)springboot应用增加preStop hook实现扩展springboot actuator节点,具体代码如下。

其中sleepSeconds可以根据项目配置。
3)在云平台配置preStop
由于暴露了prestop hook接口,如果服务直接暴露至公网,有可能被恶意扫描调用,对接口进行安全加固是很有必要的。我们在prestop hook接口增加token参数,例如:
prestop-hook-api?token=xxxxxxxxxxxxxx每个项目可以约定不同token值,并对token值进行校验,token值不对的访问将被拒绝,这样恶意扫描就无法访问到prestop hook 接口了。
代码实现我们已经封装在harmless-starter中并集成到项目模板里,这样使用者只需要配置sleepSeconds即可。
5、总结
本文主要记录了经销商技术部在保证SpringCloud应用无损下线的一些实践探索和总结,其中对SpringCloud服务下线造成损失的原因进行了比较全面的分析并提供了最终解决方案和实现,希望对其他人也有所帮助。
相关文章
Flyme5.1.6.0a(打造独特个性化的手机主题,尽享视觉盛宴)
摘要:在当今智能手机时代,个性化已经成为了用户对手机的一个基本要求。Flyme5.1.6.0a作为一款强大的主题定制平台,不仅为用户提供了海量的主题选择,而且还可以满足用户对手机外观和功...2025-11-05
我们来看一个新手甚至写了多年Java的朋友都可能不是十分确定的问题:在Java方法传参时,究竟是引用传递还是值传递?为了说明问题, 我给出一个非常简单的class定义:publicclassFoo{S2025-11-05
说明:本文主要学习Laravel的Middleware的源码设计思想,并将学习心得分享出来,希望对别人有所帮助。Laravel学习笔记之Decorator Pattern已经聊过Laravel使用了D2025-11-05
JUnit 5系列之扩展模型(Extension Model)介绍
概述环境搭建 基础入门 架构体系 扩展模型(Extension Model) 条件断言 注入 动态测试2025-11-05电脑链接错误代码651的解决办法(遇到错误代码651时,你需要知道的关键信息)
摘要:在使用电脑过程中,我们可能会遇到各种各样的错误代码。其中,错误代码651是一个常见的链接错误代码,它通常出现在使用宽带或者拨号上网时。这个错误代码意味着你的电脑无法正确连接到互联网...2025-11-05
Java是一种面向对象的编程语言,由Sun Microsystems公司在1995年的时候正式发布。直到今天,Java都一直是***的编程语言之一。如今,Java应用于各种各样的技术领域,例如网站开发2025-11-05


最新评论