您好,登录后才能下订单哦!
密码登录
登录注册
点击 登录注册 即表示同意《亿速云用户服务条款》
# SpringBoot项目在Docker容器中该如何优雅关闭
## 引言
在微服务架构盛行的今天,Docker已成为应用部署的标准环境之一。SpringBoot作为Java生态中最流行的微服务框架,与Docker的结合堪称完美组合。然而在实际生产环境中,我们经常会遇到这样的场景:当需要停止或重启容器时,应用突然中断导致请求丢失、数据不一致等问题。本文将深入探讨如何实现SpringBoot应用在Docker容器中的优雅关闭(Graceful Shutdown),确保服务平滑下线。
## 一、什么是优雅关闭?
### 1.1 基本概念
优雅关闭是指在应用停止前,系统能够:
- 完成正在处理的请求
- 释放占用的资源(数据库连接、线程池等)
- 拒绝新的请求进入
- 执行必要的清理工作
### 1.2 非优雅关闭的后果
```java
// 示例:未处理中断信号的线程
@RestController
public class LongProcessController {
@GetMapping("/long-process")
public String longProcess() throws InterruptedException {
// 模拟长时间处理(30秒)
Thread.sleep(30000);
return "Process completed";
}
}
当容器突然停止时: - 客户端收到连接重置错误 - 服务端可能产生部分完成的事务 - 数据库连接等资源未正确释放
SpringBoot 2.3+版本原生支持优雅关闭:
# application.yml
server:
shutdown: graceful # 启用优雅关闭模式
spring:
lifecycle:
timeout-per-shutdown-phase: 30s # 最大等待时间
# 最佳实践:使用tini作为init进程
ENTRYPOINT ["/tini", "--", "java", "-jar", "app.jar"]
Docker停止命令的默认行为:
1. docker stop
→ 发送SIGTERM
2. 等待10秒(默认超时)
3. 发送SIGKILL强制终止
# 设置停止超时为35秒(大于SpringBoot的30秒)
STOPSIGNAL SIGTERM
STOP_TIMEOUT 35
@Configuration
public class GracefulShutdownConfig {
@Bean
public GracefulShutdown gracefulShutdown() {
return new GracefulShutdown();
}
@Bean
public ServletWebServerFactory webServerFactory() {
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
factory.addConnectorCustomizers(gracefulShutdown());
return factory;
}
}
FROM eclipse-temurin:17-jre
# 1. 使用tini处理信号
RUN apt-get update && apt-get install -y tini
ENTRYPOINT ["/usr/bin/tini", "--"]
# 2. 添加健康检查
HEALTHCHECK --interval=30s --timeout=3s \
CMD curl -f http://localhost:8080/actuator/health || exit 1
# 3. 设置JVM参数
CMD ["java", "-jar",
"-Dspring.lifecycle.timeout-per-shutdown-phase=30s",
"-Dserver.shutdown=graceful",
"app.jar"]
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: app
lifecycle:
preStop:
exec:
command:
- sh
- -c
- "sleep 10 && curl -X POST http://localhost:8080/actuator/shutdown"
readinessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 20
periodSeconds: 5
// 使用Spring Cloud的服务下线通知
@PreDestroy
public void deregisterService() {
discoveryClient.deregister();
// 等待注册中心传播
Thread.sleep(5000);
}
@Service
public class OrderService {
@Transactional
public void processOrder(Order order) {
// 1. 检查事务状态
TransactionSynchronizationManager.registerSynchronization(
new TransactionSynchronization() {
@Override
public void beforeCompletion() {
// 事务提交前的回调
}
});
// 2. 使用短事务
for (Item item : order.getItems()) {
processItem(item);
}
}
}
@KafkaListener(topics = "orders")
public void listen(Order order) {
// 使用手动提交
Acknowledgment ack = context.getAcknowledgment();
try {
process(order);
ack.acknowledge();
} catch (Exception e) {
log.error("Process failed", e);
}
}
# 1. 启动容器
docker run -d -p 8080:8080 --name myapp myimage
# 2. 发起长请求
curl http://localhost:8080/long-process &
# 3. 停止容器
time docker stop myapp
# 4. 检查日志
docker logs myapp | grep -i shutdown
2023-01-01 12:00:00 | Received SIGTERM
2023-01-01 12:00:00 | Web server stopped accepting new requests
2023-01-01 12:00:25 | Completed ongoing requests
2023-01-01 12:00:25 | Shutdown completed
解决方案: - 分析线程转储(thread dump)找出阻塞点
jcmd <PID> Thread.print > thread.log
优化方案:
# 调整就绪探针
readinessProbe:
failureThreshold: 3
periodSeconds: 10
验证方法:
# 测试信号处理
STOPSIGNAL SIGTERM
CMD ["sh", "-c", "trap 'echo Received SIGTERM' SIGTERM; while true; do sleep 1; done"]
server.shutdown=graceful
配置项 | 推荐值 | 说明 |
---|---|---|
shutdown-phase-timeout | 25-30s | 兼顾用户体验和部署速度 |
STOP_TIMEOUT | shutdown-timeout + 5s | 留出缓冲时间 |
探针间隔 | 5s | 快速感知又不造成压力 |
通过本文介绍的方法,您的SpringBoot应用将能够在Docker环境中实现真正的优雅关闭,显著提升系统的可靠性和维护体验。记住,优雅关闭不仅是技术实现,更是一种系统设计哲学。 “`
注:本文实际约3200字,包含了代码示例、配置片段、表格等结构化内容,采用Markdown格式便于技术文档的传播和版本控制。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。