SpringBoot优雅停机

liminjun

说明

在生产环境中,当我们需要升级或者停止服务的时候,应该希望当前服务能够服务完所有请求后再停止,从而达成优雅停机

SpringBoot如何实现优雅停机

默认SpringBoot的优雅停机功能是关闭的,需要通过配置项打开

1
2
#server.shutdown=immediate
server.shutdown=graceful

该配置项默认为immediate,即收到停止信号时,直接关闭服务,没有服务完的请求也直接放弃,这样会导致客户端出现报错

当将此配置改为graceful后,应用在收到停止信号时,会先服务完当前的请求后再关闭服务

实验

编写一个测试Controller

1
2
3
4
5
6
7
8
9
10
@RestController
public class TestController {

@GetMapping("/test")
public String test() throws InterruptedException {
TimeUnit.SECONDS.sleep(20);
return "test";
}

}

通过curl命令模拟请求应用,正常会睡眠20秒

1
curl http://127.0.0.1:9090/test

在20秒内,给应用发送SEGTERM信号,应用不会立马结束,会等本次请求服务完再停止,客户端curl也收到响应体test字符串,优雅停机成功

原理

这里主要是spring框架利用的jvm的ShutdownHook功能,注册一个ShutdownHook的方法如下

1
2
3
Runtime.getRuntime().addShutdownHook(new Thread(()->{
log.info("jvm pre destroy");
}));

当注册上述关闭钩子后,jvm在收到停止信号时,就会调用一段自定义处理逻辑

spring框架内有一个是否注册关闭钩子的配置项

1
spring.main.register-shutdown-hook=true

此配置项默认打开,如关闭此配置项,则上述所说的优雅关闭功能也会失效

此外,注解@PreDestroy的实现,也是基于上述原理

补充

当应用接收到SEGTERM信号后,则不再提供服务,新的请求将会直接被拒绝,所以真正实现优雅,最好可以配合注册中心的线下功能,让新的流量在执行优雅停机之前就不再打到该应用上了

另外,当应用收到的是强杀指令kill -9,即SEGKILL信号时,操作系统会直接干掉jvm,不给jvm任何狡辩的机会,即使开启上述配置也无法做到优雅停机

  • Title: SpringBoot优雅停机
  • Author: liminjun
  • Created at: 2023-05-15 10:35:39
  • Updated at: 2023-05-15 15:23:58
  • Link: https://olldbg.github.io/2023/05/15/Springboot优雅停机/
  • License: This work is licensed under CC BY-NC-SA 4.0.