优雅停机期间,Kubernetes会发送SIGTERM信号,Spring Boot应用如何捕获此信号并等待进行中的请求处理完成?
2条回答 默认 最新
檀越@新空间 2025-12-02 14:47关注下午好🌅🌅🌅
本答案参考通义千问在 Kubernetes 中,当执行**优雅停机(graceful shutdown)**时,Kubernetes 会向容器发送 SIGTERM 信号。默认情况下,Spring Boot 应用会在收到 SIGTERM 后立即终止,这可能导致正在进行的请求被中断,影响用户体验和数据一致性。
为了确保应用能够捕获 SIGTERM 信号并等待所有当前请求处理完成后再退出,我们需要在 Spring Boot 应用中实现自定义的关闭逻辑。
✅ 解决方案概述
以下是实现 Spring Boot 应用优雅停机的完整步骤:
1. 注册一个 Shutdown Hook
Spring Boot 提供了
SpringApplication的setExitCodeGenerator方法,也可以通过注册ShutdownHook来监听系统关闭事件。2. 捕获 SIGTERM 信号
使用 Java 的
Signal类来监听系统信号,并触发自定义的关闭逻辑。3. 等待进行中的请求完成
在关闭过程中,需要确保所有正在处理的请求完成后再退出,可以通过
CountDownLatch或CompletableFuture实现。4. 设置合适的 grace period
Kubernetes 的
terminationGracePeriodSeconds需要合理设置,以确保应用有足够时间完成关闭流程。
🛠️ 详细实现步骤
1. 创建自定义的 Shutdown Hook
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import java.util.concurrent.CountDownLatch; @SpringBootApplication public class Application { private static final CountDownLatch shutdownLatch = new CountDownLatch(1); public static void main(String[] args) { SpringApplication app = new SpringApplication(Application.class); app.setExitCodeGenerator(context -> { // 在这里可以添加关闭逻辑 System.out.println("Shutting down..."); return 0; }); // 注册 SIGTERM 信号处理 Signal.handle(new Signal("TERM"), signal -> { System.out.println("Received SIGTERM, initiating graceful shutdown..."); shutdownLatch.countDown(); // 触发关闭逻辑 }); app.run(args); try { shutdownLatch.await(); // 等待关闭信号 } catch (InterruptedException e) { Thread.currentThread().interrupt(); System.err.println("Shutdown interrupted: " + e.getMessage()); } System.out.println("Application is now shutting down."); } }2. 在 Controller 中模拟异步请求处理
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; @RestController public class TestController { @GetMapping("/slow") public String slowRequest() { CompletableFuture.runAsync(() -> { try { TimeUnit.SECONDS.sleep(5); // 模拟耗时操作 System.out.println("Request completed."); } catch (InterruptedException e) { Thread.currentThread().interrupt(); System.err.println("Request interrupted: " + e.getMessage()); } }); return "Request started."; } }3. 配置 Kubernetes 的 terminationGracePeriodSeconds
在 Deployment 中设置合理的
terminationGracePeriodSeconds,例如:apiVersion: apps/v1 kind: Deployment metadata: name: my-springboot-app spec: replicas: 1 strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 maxUnavailable: 0 template: spec: containers: - name: app image: my-springboot-app:latest lifecycle: preStop: exec: command: ["sh", "-c", "sleep 10"] ports: - containerPort: 8080 terminationGracePeriodSeconds: 30⚠️ 注意:
preStop是 Kubernetes 提供的一种机制,在 Pod 被终止前执行,可以配合 SIGTERM 使用。
🧠 关键点总结
- 优雅停机的关键是等待所有请求完成后再退出。
- 使用 CountDownLatch 或 CompletableFuture 可以控制关闭流程。
- Kubernetes 的 terminationGracePeriodSeconds 必须足够长,以容纳应用的关闭逻辑。
- Spring Boot 的 shutdown hook 和 SIGTERM 信号可以结合使用,实现更灵活的控制。
🔍 附加建议
- 如果你使用的是 Spring WebFlux 或响应式框架,应使用
reactor-core的Mono或Flux来管理异步请求。 - 对于生产环境,建议使用 Health Check Endpoint 来通知 Kubernetes 应用已经准备好停止。
如需进一步优化,还可以考虑集成 Spring Actuator 的
/actuator/shutdown接口,或者使用 Spring Boot Admin 进行健康监控与管理。本回答被题主选为最佳回答 , 对您是否有帮助呢?解决 无用评论 打赏 举报