知其然要知其所以然,探索每一个知识点背后的意义,你知道的越多,你不知道的越多,一起学习,一起进步,如果文章感觉对您有用的话,关注、收藏、点赞,有困惑的地方请评论,我们一起交流!
Spring Boot 优雅停机(Graceful Shutdown)实现指南
在分布式系统中,服务的优雅停机(Graceful Shutdown)是确保业务连续性的重要机制。Spring Boot 通过 内嵌服务器支持 和 生命周期管理 实现了这一功能,以下是具体实现方式和配置细节:
1. 优雅停机的核心目标
- 停止接收新请求:关闭监听端口,不再接受新连接。
- 等待处理中的请求完成:允许正在执行的请求继续处理直至超时。
- 释放资源:关闭数据库连接池、线程池等资源。
- 避免数据不一致:确保事务完整性,防止中途中断。
2. 基于内嵌服务器的优雅停机配置
Spring Boot 从 2.3 版本 开始,为 Tomcat、Jetty、Undertow 等内嵌服务器内置了优雅停机支持。
2.1 启用优雅停机
在 application.properties
或 application.yml
中配置:
yaml
server:
shutdown: graceful # 启用优雅停机模式
spring:
lifecycle:
timeout-per-shutdown-phase: 30s # 等待请求完成的超时时间(默认30秒)
2.2 不同服务器的行为
服务器 | 优雅停机行为 |
---|---|
Tomcat | 停止接收新请求,等待处理中的请求完成,超时后强制关闭。 |
Jetty | 停止接收新连接,等待活跃请求完成。 |
Undertow | 关闭监听端口,等待活跃请求完成。 |
2.3 验证停机流程
-
发送停机信号:
-
通过
SIGTERM
信号(Kill 命令)或 Actuator 端点关闭应用。 -
使用 Actuator 端点需要添加依赖和配置:
xml<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
yamlmanagement: endpoint: shutdown: enabled: true endpoints: web: exposure: include: shutdown
-
发送 POST 请求关闭应用:
bashcurl -X POST http://localhost:8080/actuator/shutdown
-
-
观察日志:
arduino2023-10-05 14:20:00 INFO o.s.b.w.e.tomcat.GracefulShutdown : Commencing graceful shutdown. Waiting for active requests to complete 2023-10-05 14:20:30 INFO o.s.b.w.e.tomcat.GracefulShutdown : Graceful shutdown complete
3. 自定义停机逻辑扩展
3.1 监听停机事件
通过实现 ApplicationListener<ContextClosedEvent>
监听上下文关闭事件:
java
@Component
public class GracefulShutdownListener implements ApplicationListener<ContextClosedEvent> {
@Override
public void onApplicationEvent(ContextClosedEvent event) {
//dubbo关闭
DubboBootstrap.getInstance().stop();
// 执行自定义清理逻辑(如关闭线程池、释放资源)
ExecutorService executor = event.getApplicationContext().getBean(ExecutorService.class);
executor.shutdown();
try {
if (!executor.awaitTermination(30, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
3.2 使用 @PreDestroy
注解
在 Bean 销毁前执行清理逻辑:
java
@Service
public class DatabaseService {
@PreDestroy
public void cleanup() {
// 关闭数据库连接
DataSource dataSource = ...;
dataSource.close();
}
}
4. 集成 Kubernetes 的优雅停机
在 Kubernetes 中,结合 Pod 生命周期钩子 实现优雅停机:
4.1 配置 PreStop Hook
在 Deployment 配置中添加 preStop
钩子,延迟终止进程:
yaml
spec:
template:
spec:
containers:
- name: app
lifecycle:
preStop:
exec:
command: ["sh", "-c", "sleep 30"] # 等待30秒后发送SIGTERM
terminationGracePeriodSeconds: 60 # 总宽限期(包括preStop)
4.2 配合就绪探针
在停机前标记服务不可用:
yaml
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
5. 常见问题与解决方案
问题 | 解决方案 |
---|---|
停机超时后仍有未完成请求 | 调整 spring.lifecycle.timeout-per-shutdown-phase 延长等待时间。 |
线程池任务未执行完 | 自定义 ExecutorService 并在停机时调用 shutdown() 和 awaitTermination() 。 |
数据库连接未关闭 | 通过 @PreDestroy 或 DisposableBean 显式关闭连接池。 |
Kubernetes 强制终止 Pod | 确保 terminationGracePeriodSeconds 大于优雅停机超时时间。 |
6. 验证优雅停机效果
-
发送长耗时请求 :
bashcurl http://localhost:8080/long-task
-
触发停机 :
bashcurl -X POST http://localhost:8080/actuator/shutdown
-
观察结果 :
- 新请求返回
503 Service Unavailable
。 - 正在处理的请求继续执行直至完成或超时。
- 新请求返回
总结
通过 内嵌服务器配置 、生命周期钩子 和 Kubernetes 集成,Spring Boot 实现了开箱即用的优雅停机功能。关键配置包括:
- 启用
server.shutdown=graceful
。 - 设置合理的超时时间。
- 结合 Actuator 端点或 Kubernetes 生命周期管理。