spring boot优雅停机,拒绝kill -9

本文介绍了SpringBoot应用的优雅停机机制,包括其重要性和默认行为。在2.3版本中,SpringBoot支持了优雅停机功能,允许在关闭时等待活跃请求完成。配置中通过`server.shutdown=graceful`启用该功能,可以避免数据不一致和事务未完成的问题。同时,文章探讨了不同Web容器的优雅停机行为,以及如何通过`/actuator/shutdown`端点实现优雅关机。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 什么是优雅停机

  • graceful shutdown

  • 配置体验

  • 相关知识

什么是优雅停机

第一步:停止接收请求和内部线程。
第二步:判断是否有线程正在执行。
第三步:等待正在执行的线程执行完毕。
第四步:停止容器。

先来一段简单的代码,如下:

@RestController
public class DemoController {
 @GetMapping("/demo")
 public String demo() throws InterruptedException {
     // 模拟业务耗时处理流程
  Thread.sleep(20 * 1000L);
  return "hello";
 }
}

当我们流量请求到此接口执行业务逻辑的时候,若服务端此时执行关机 (kill),spring boot 默认情况会直接关闭容器(tomcat 等),导致此业务逻辑执行失败。在一些业务场景下:会出现数据不一致的情况,事务逻辑不会回滚。

graceful shutdown

在最新的 spring boot 2.3 版本,内置此功能,不需要再自行扩展容器线程池来处理, 目前 spring boot 嵌入式支持的 web 服务器(Jetty、Reactor Netty、Tomcat 和 Undertow)以及反应式和基于 Servlet 的 web 应用程序都支持优雅停机功能。我们来看下如何使用:

当使用server.shutdown=graceful启用时,在 web 容器关闭时,web 服务器将不再接收新请求,并将等待活动请求完成的缓冲期。

配置体验

此处支持的 shutdown 行为,我们看下 源码枚举如下:

/**
 * Configuration for shutting down a {@link WebServer}.
 *
 * @author Andy Wilkinson
 * @since 2.3.0
 */
public enum Shutdown {
 /**
  * 优雅停机 (限期停机)
  *
  */
 GRACEFUL,

 /**
  * 立即停机
  */
 IMMEDIATE;

}

缓冲期 timeout-per-shutdown-phase 配置

  • 默认时间为 30S, 意味着最大等待 30S,超时候无论线程任务是否执行完毕都会停机处理,一定要合理合理设置。

效果体验

  •  

    1. 请求服务端接口

  •  

    1. 执行关闭应用

  •  

    1. 服务端接到关闭指令

    2. 2020-05-17 18:28:28.940  INFO 60341 --- [extShutdownHook] o.s.b.w.e.tomcat.GracefulShutdown        : Commencing graceful shutdown. Waiting for active requests to complete
      2020-05-17 18:28:45.923  INFO 60341 --- [tomcat-shutdown] o.s.b.w.e.tomcat.GracefulShutdown        : Graceful shutdown complete

  •  

    1. 接口请求执行完成

相关知识

  1. 关于此处执行kill -2 而不是 kill -9

  • kill -2 相当于快捷键 Ctrl + C 会触发 Java 的 ShutdownHook 事件处理(优雅停机或者一些后置处理可参考以下源码)

//ApplicationContext
 @Override
 public void registerShutdownHook() {
  if (this.shutdownHook == null) {
   // No shutdown hook registered yet.
   this.shutdownHook = new Thread(SHUTDOWN_HOOK_THREAD_NAME) {
    @Override
    public void run() {
     synchronized (startupShutdownMonitor) {
      doClose();
     }
    }
   };
   Runtime.getRuntime().addShutdownHook(this.shutdownHook);
  }
 }

  • kill -9,暴力美学强制杀死进程,不会执行 ShutdownHook

  1. 通过 actuate 端点实现优雅停机

POST 请求 /actuator/shutdown 即可执行优雅关机。

源码解析

@Endpoint(id = "shutdown", enableByDefault = false)
public class ShutdownEndpoint implements ApplicationContextAware {

 @WriteOperation
 public Map<String, String> shutdown() {
  Thread thread = new Thread(this::performShutdown);
  thread.setContextClassLoader(getClass().getClassLoader());
  thread.start();
 }

 private void performShutdown() {
  try {
   Thread.sleep(500L);
  }
  catch (InterruptedException ex) {
   Thread.currentThread().interrupt();
  }

  // 此处close 逻辑和上边 shutdownhook 的处理一样
  this.context.close();
 }
}

  1. 不同 web 容器优雅停机行为区别

容器停机行为取决于具体的 web 容器行为

web 容器名称行为说明
tomcat 9.0.33+停止接收请求,客户端新请求等待超时。
Reactor Netty停止接收请求,客户端新请求等待超时。
Undertow停止接收请求,客户端新请求直接返回 503。
### 如何处理 `kill -9` 无法找到进程或目标进程未被终止 当尝试使用 `kill -9` 终止某个进程时,如果发现进程不存在或者未能成功终止,通常可能是由于以下几个原因造成的: #### 1. **确认进程是否存在** 需要确保所操作的目标进程确实存在。可以使用以下命令来查找特定的进程: ```bash ps aux | grep <PID> ``` 如果返回为空,则说明该进程已经不存在。 此外,在某些情况下,即使进程看似存在,但由于权限不足或其他特殊状态(如僵尸进程),可能导致其不可见或难以正常管理[^1]。 #### 2. **检查父进程关系** 若目标进程始终无法被彻底清除,可能是因为它依赖于一个活跃的父进程 (Parent Process ID, PPID),而只有在父进程存活的情况下才能维持运行。此时需先定位并结束父进程: ```bash cd /proc/<PID> && cat status ``` 上述指令能够展示当前进程的状态详情,其中包括它的PPID字段。一旦获取到具体的PPID编号,就可以按照如下方式依次销毁父子级联结构: ```bash kill -9 <PPID> kill -9 <PID> ``` #### 3. **考虑系统资源限制因素** 对于部分应用环境而言,可能存在操作系统级别施加的各种约束条件,比如CPU配额、内存上限等设置可能会间接引发类似现象的发生。例如Flume Agent因受控于MDE服务组内的固定容量分配机制而导致频繁遭遇OOM(Kill Out Of Memory)[^3]。针对这种情况建议重新规划资源配置方案或者调整对应参数阈值范围以适应实际需求场景的要求。 #### 4. **排查Spring Boot线程池相关问题** 当涉及到基于Java框架构建的服务端程序实例化失败案例分析时,我们注意到一些特殊的多线程执行模型设计缺陷也可能成为潜在诱因之一。特别是对于那些采用了自定义实现版本而非官方推荐标准库组件开发出来的异步任务调度逻辑来说更是如此——它们往往缺乏完善的错误恢复能力以及合理的超时退出策略安排[^4]。因此有必要深入审查内部工作流程细节,并针对性优化改进代码质量水平从而有效规避此类风险事件再次发生概率提升整体稳定性表现指标得分情况有所改善最终达到预期效果目的为止才算完成整个修复过程全部环节内容覆盖全面无遗漏之处可言矣乎哉! ```python def graceful_shutdown(): try: # 实现优雅停机逻辑... pass except Exception as e: print(f"Error during shutdown: {e}") ``` --- ###
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值