同步操作将从 JustryDeng/notebook 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
Web 容器优雅停机行为指的是在关闭容器时,让当前正在处理的请求处理完成或者等待一段时间,让正在处理的请求完成后再关闭容器,而不是直接强制终止正在处理的请求。这样可以避免正在处理的请求被中断,从而提高系统的可用性和稳定性
一般来说,Web 容器的优雅停机行为需要满足以下几个条件:
如果没有优雅停机,服务器此时直接直接关闭(kill -9),那么就会导致当前正在容器内运行的业务直接失败,在某些特殊的场景下产生脏数据
在服务器执行关闭(kill -2)时,会预留一点时间使容器内部业务线程执行完毕;增加了优雅停机配置后, 此时容器也不允许新的请求进入。
目前版本(2.3.4.RELEASE)的Spring Boot 优雅停机支持Jetty
, Reactor Netty
, Tomcat
和 Undertow
以及反应式和基于 Servlet 的 web 应用程序都支持优雅停机功能。
新请求的处理方式跟web服务器有关,Reactor Netty、 Tomcat将停止接入请求,Undertow的处理方式是返回503。
具体行为,如下表所示:
web 容器名称 | 行为说明 |
---|---|
tomcat 9.0.33+ | 停止接收请求,客户端新请求等待超时 |
Reactor Netty | 停止接收请求,客户端新请求等待超时 |
Undertow | 停止接收请求,客户端新请求直接返回 503 |
不同的 Web 容器实现优雅停机的方式可能会有所不同,但是一般都会提供相关的配置选项或者 API 接口来实现这个功能。
另外,和SpringBoot内嵌的WEB服务器类似,其他的非SpringBoot内嵌WEB服务器,也可以进行设置。
下面是 Nginx 和 Apache 的优雅停机配置:
server:
# 设置为优雅停机。默认为immediate,立即停机
shutdown: graceful
# 设置缓冲参数timeout-per-shutdown-phase
# 在timeout-per-shutdown-phase时间内的某个时间点如果线程执行完毕了,则会马上完成停机
# 在timeout-per-shutdown-phase时间内如果线程无法执行完毕,则一旦过了timeout-per-shutdown-phase时间,则会被强制停机
spring:
lifecycle:
timeout-per-shutdown-phase: 30s
正常部署启动程序,然后使用以下方式进行停止程序,即可触发优雅停机
方式一:kill {进程id}
kill {进程id}
,等价于kill -15 {进程id}
,表示终止进程;不能用kill -9 {进程id}
,kill -9表示杀死进程,会立即杀死进程
方式二:调用/actuator/shutdown
端点
提示:前提是,暴露了此端点,才可以调用
测试步骤1:准备一个spring-boot项目(本人用的是spring-boot 2.6.4
版本),然后按照第一步配置启用优雅停机支持
测试步骤2:编写一个简单的测试代码
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@RequestMapping("/test")
public String test() throws InterruptedException {
Thread.sleep(10000);
return RandomStringUtils.random(10 , true, true);
}
}
测试步骤3:打包项目,部署到linux后启动项目
在IDE(如:idea)中直接启动也可
测试步骤4:依次进行以下步骤,然后观察结果及程序日志
kill {进程id}
指令1的请求最后是成功的:
因为这时还没触发优雅停机
2的操作截图:
触发优雅停机,此时1还在执行中,3还没执行
3的请求是失败的:
因为tomcat已经收到优雅停机指令了,所以拒绝了3的请求,但是接受优雅停机前收到1的请求还是会执行完毕才停机的
最后我们观察程序日志
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.6.4)
2023-06-11 12:37:29.660 INFO 31419 --- [ main] com.ideaaedi.demo.StartUp : Starting StartUp v1.0.0 using Java 11.0.1 on iZm5ea6hfv6pmn30ook2l7Z with PID 31419 (/temp/demo-1.0.0.jar started by root in /temp)
2023-06-11 12:37:29.671 INFO 31419 --- [ main] com.ideaaedi.demo.StartUp : No active profile set, falling back to 1 default profile: "default"
2023-06-11 12:37:33.036 INFO 31419 --- [ main] c.i.c.register.FeatureRegistrar : registry bean 'parameterRecorderAdvice' with ConstructorArg includePrefixes -> [com.ideaaedi], excludePrefixes -> [], parameterHandleMode -> USE_JSON, pretty -> true, ignoreParamTypes -> []
2023-06-11 12:37:36.388 INFO 31419 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2023-06-11 12:37:36.407 INFO 31419 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2023-06-11 12:37:36.407 INFO 31419 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.58]
2023-06-11 12:37:37.242 INFO 31419 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2023-06-11 12:37:37.243 INFO 31419 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 6875 ms
2023-06-11 12:37:37.752 INFO 31419 --- [ main] c.i.c.aop.ParameterRecorderAdvice : Set LocalVariableTableParameterNameDiscoverer as parameterNameDiscoverer.
2023-06-11 12:37:39.695 INFO 31419 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2023-06-11 12:37:39.723 INFO 31419 --- [ main] com.ideaaedi.demo.StartUp : Started StartUp in 11.118 seconds (JVM running for 12.13)
2023-06-11 12:38:32.748 INFO 31419 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2023-06-11 12:38:32.748 INFO 31419 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2023-06-11 12:38:32.749 INFO 31419 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 0 ms
2023-06-11 12:38:32.796 INFO 31419 --- [nio-8080-exec-1] c.i.c.aop.ParameterRecorderAdvice :
// 这是aop工具记录的请求入参,说明1的请求进来了
[the way in] request-path[] Class#Method -> com.ideaaedi.demo.controller.TestController#test, without any parameters
// 程序接收到了优雅停机指令,Commencing graceful shutdown. Waiting for active requests to complete
2023-06-11 12:38:34.593 INFO 31419 --- [ionShutdownHook] o.s.b.w.e.tomcat.GracefulShutdown : Commencing graceful shutdown. Waiting for active requests to complete
2023-06-11 12:38:42.965 INFO 31419 --- [nio-8080-exec-1] c.i.c.aop.ParameterRecorderAdvice :
// 这是aop工具记录的请求出参,说明1的请求结束了
[the way out] request-path[] Class#Method -> com.ideaaedi.demo.controller.TestController#test
return type -> class java.lang.String
return result -> "6o6cDmLi3n"
// 优雅停机完成
2023-06-11 12:38:43.033 INFO 31419 --- [tomcat-shutdown] o.s.b.w.e.tomcat.GracefulShutdown : Graceful shutdown complete
由此可见,优雅停机的目的达到了
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。