Seal^_^ 2025-12-02 14:44 采纳率: 72.6%
浏览 2
已结题

优雅停机期间,Kubernetes会发送SIGTERM信号,Spring Boot应用如何捕获此信号并等待进行中的请求处理完成?

优雅停机期间,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 提供了 SpringApplicationsetExitCodeGenerator 方法,也可以通过注册 ShutdownHook 来监听系统关闭事件。

    2. 捕获 SIGTERM 信号

    使用 Java 的 Signal 类来监听系统信号,并触发自定义的关闭逻辑。

    3. 等待进行中的请求完成

    在关闭过程中,需要确保所有正在处理的请求完成后再退出,可以通过 CountDownLatchCompletableFuture 实现。

    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-coreMonoFlux 来管理异步请求。
    • 对于生产环境,建议使用 Health Check Endpoint 来通知 Kubernetes 应用已经准备好停止。

    如需进一步优化,还可以考虑集成 Spring Actuator/actuator/shutdown 接口,或者使用 Spring Boot Admin 进行健康监控与管理。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

问题事件

  • 系统已结题 12月11日
  • 已采纳回答 12月3日
  • 创建了问题 12月2日