赞
踩
spring boot默认是不会优雅关闭的,在没有启用任何优雅关闭机制的情况下,Spring Boot 应用程序将在收到信号后立即终止,此时一些没有执行完的程序就会直接退出,可能导致业务逻辑执行失败,在一些业务场景下会出现数据不一致的情况。
不使用优雅停机:1.在一体化系统中录入拨款申请等场景,直接结束进程,会导致用户录入以及后续的记账等流程直接中断。2.在使用定时任务执行一些规则时,插入表数据未用事务时,会导致一批执行的规则数据不一致,还要筛选哪些规则执行哪些规则没执行。3.分布式业务存在多线程的情况下,执行关联的业务逻辑处理,有些业务逻辑可能没执行,也会造成数据不一致的情况。4.在服务调用外部接口时,会直接调用失败。
使用优雅停机:1.用户可以把当前的操作请求执行完才会停止服务。2.对于定时任务可以避免规则部分执行的情况。3.对于多线程执行业务逻辑场景,可以避免数据不一致的情况。4.服务在调用外部接口时,会在等待的时间内调用外部接口成功。
注意:以上举例的场景,仅限于执行业务的时间在优雅停机设置的容忍时间(设置的强制结束时间)内,即优雅停机可以很大几率解决一些问题。
spring boot 2.3以下版本,引入spring-boot-starter-actuator
监控类库,它其中一个功能支持优雅关闭。
spring boot 2.3版本开始,自己集成了优雅关闭,无需再引入上方类库即可实现优雅关闭。
注意:spring-boot-starter-actuator
文档中说是支持优雅关闭,但仅仅是spring层面上的,不和tomcat等容器挂钩,直到spring boot 2.3开启自带的优雅关闭后才真正能实现,也就是说2.3之前的版本根本实现不了优雅关闭,需要自己来进一步按照使用的容器做处理才行。
在application.yml中增加:
# 开启优雅关闭
server:
shutdown: graceful
# 配置强制结束时间,不配置的话默认30s
spring:
lifecycle:
timeout-per-shutdown-phase: 30s
spring-boot-starter-actuator
的maven类库 <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
import com.tongweb.container.connector.Connector; import com.tongweb.springboot.v1.x.embed.TongWebConnectorInitializer; import lombok.extern.slf4j.Slf4j; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextClosedEvent; import java.util.concurrent.Executor; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** * 优雅关闭 * @Author:yangshen * Date:2023年10月16日 */ @Slf4j public class GracefulShutdown implements TongWebConnectorInitializer, ApplicationListener<ContextClosedEvent> { private volatile Connector connector; /** * 30s强制关闭 当超过30秒时,会强制结束进程 */ private static final int TIMEOUT = 30; /** * 关闭时触发 * * @param event */ @Override public void onApplicationEvent(ContextClosedEvent event) { this.connector.pause(); Executor executor = this.connector.getProtocolHandler().getExecutor(); if (executor instanceof ThreadPoolExecutor) { try { ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor; threadPoolExecutor.shutdown(); if (!threadPoolExecutor.awaitTermination(TIMEOUT, TimeUnit.SECONDS)) { log.warn("TongWeb thread pool did not shut down gracefully within " + TIMEOUT + " seconds. Proceeding with forceful shutdown"); } } catch (InterruptedException ex) { Thread.currentThread().interrupt(); } } } /** * 自定义链接 */ @Override public void init(Connector connector) { this.connector = connector; } }
import com.boss.payreal.controller.GracefulShutdown; import com.tongweb.springboot.v1.x.embed.TongWebEmbedServletContainerFactory; import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer; import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * 优雅停机配置: * @Author: yangshen * Date: 2023年10月16日 */ @Configuration public class ShutdownConfig { /** * 优雅关闭bean,用于接受shutdown事件 */ @Bean public GracefulShutdown gracefulShutdown() { return new GracefulShutdown(); } /** * tongWeb配置优雅关闭 */ @Bean public EmbeddedServletContainerCustomizer tongWebCustomizer() { return new EmbeddedServletContainerCustomizer() { @Override public void customize(ConfigurableEmbeddedServletContainer container) { if (container instanceof TongWebEmbedServletContainerFactory) { ((TongWebEmbedServletContainerFactory) container) .addConnectorCustomizers(gracefulShutdown()); } } }; } }
无论是springboot1.x版本还是2.3以上版本,皆有两种触发优雅停机的方式:
1.通过 curl -X POST http://host:port/actuator/shutdown
2.通过使用kill pid 命令,不能使用kill -9
两种方式的区别:
方式1 不安全,需要在配置文件中额外配置shutdown端点开启,配置额外的自定义端口,以及自定义路径来保证安全性,而且这种方式只是暂停容器接受请求,并不会结束进程,还需要在脚本里加kill-9 pid 才会结束进程实现优雅停机,比较繁琐。
方式2 比较安全,脚本里直接kill pid即可,会实现优雅停机并且结束进程,springboot1.x版本不用配置yml文件中的监控相关配置,直接用配置类即可
方式1需要增加如下配置:
#监控相关配置 management: endpoint: # 开启 shutdown: enabled: true endpoints: web: # 只允许shutdown,为了安全,其它想要监控自行配置 exposure: include: "shutdown" # 自定义请求路径,为了安全 base-path: /xxx server: #自定义请求端口,为了安全 port: 7080
因为目前我们的系统springboot版本为1.5.12,故采用springboot1.X的优雅停机方案,只需要引入spring-boot-starter-actuator
的maven类库,在配置类中实现代码即可,无需配置yml配置文件中的关于actuator的配置,调用优雅停机方式采用方式2,kill pid触发优雅停机。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。