重学SpringBoot3-怎样优雅停机

更多SpringBoot3内容请关注我的专栏:《SpringBoot3》

期待您的点赞👍收藏⭐评论✍

重学SpringBoot3-怎样优雅停机

  • [1. 什么是优雅停机?](#1. 什么是优雅停机?)
  • [2. Spring Boot 3 优雅停机的配置](#2. Spring Boot 3 优雅停机的配置)
  • [3. Tomcat 和 Reactor Netty 的优雅停机机制](#3. Tomcat 和 Reactor Netty 的优雅停机机制)
    • [3.1 Tomcat 优雅停机](#3.1 Tomcat 优雅停机)
    • [3.2 Reactor Netty 优雅停机](#3.2 Reactor Netty 优雅停机)
  • [4. 优雅停机的流程](#4. 优雅停机的流程)
  • [5. 实现优雅停机的完整示例](#5. 实现优雅停机的完整示例)
    • [5.1 代码示例](#5.1 代码示例)
    • [5.2 IDEA 停止服务](#5.2 IDEA 停止服务)
    • [5.3 测试优雅停机](#5.3 测试优雅停机)
  • [6. 负载均衡器中的停机策略](#6. 负载均衡器中的停机策略)
  • [7. 优雅停机的注意事项](#7. 优雅停机的注意事项)
  • [8. 总结](#8. 总结)

在现代微服务架构中,优雅停机(Graceful Shutdown)是一项重要功能,可以确保服务在关闭时处理完所有当前请求,避免突然终止连接或丢失数据。Spring Boot 3 提供了对优雅停机的内置支持,允许在关闭应用程序上下文期间为现有请求设置一个宽限期,同时防止新请求进入。本文将详细介绍 Spring Boot 3 的优雅停机机制,重点分析 Tomcat 和 Reactor Netty 两种常用的嵌入式 Web 服务器的优雅停机流程。

1. 什么是优雅停机?

优雅停机的目标是在服务关闭时:

  • 允许当前的处理请求在指定的宽限期内完成。
  • 阻止新的请求进入。
  • 向外部监控或负载均衡器标记服务为不可用。

这种机制可以确保服务在维护或版本升级时避免数据丢失和请求中断,提供更高的稳定性和可用性。

2. Spring Boot 3 优雅停机的配置

在 Spring Boot 3 中,我们可以使用 server.shutdown 配置来开启优雅停机,并指定宽限期。配置项如下:

yaml 复制代码
server:
  shutdown: "graceful" # 开启优雅停机
spring:
  lifecycle:
    timeout-per-shutdown-phase: "20s"  # 停机的宽限期,默认为 30 秒

此配置项适用于所有四种嵌入式 Web 服务器:Tomcat、Jetty、Reactor Netty 和 Undertow。

注意 :Spring Boot 3 默认禁用优雅停机,需要将 server.shutdown 设置为 graceful 以启用。

3. Tomcat 和 Reactor Netty 的优雅停机机制

Spring Boot 3 支持在不同的 Web 服务器上实现优雅停机。以下是 Tomcat 和 Reactor Netty 的具体停机方式:

3.1 Tomcat 优雅停机

使用Tomcat的优雅关机需要Tomcat 9.0.33或更高版本,在 Tomcat 上启用优雅停机后,当收到关闭信号时,它将停止接受新的连接请求,并在网络层阻止传入流量:

  • 阻止新请求:一旦启动关闭流程,Tomcat 将在网络层拒绝新的请求连接。
  • 完成现有请求:Tomcat 会确保已有请求在指定的宽限期内完成。如果请求未完成且宽限期到达,将强制终止。

注意:若某些请求未在宽限期内完成,则这些请求将被中断。

3.2 Reactor Netty 优雅停机

Reactor Netty 是 Spring WebFlux 默认使用的非阻塞式 Web 服务器,适合响应式编程。Reactor Netty 的优雅停机实现方式如下:

  • 网络层停止:当关闭信号到达,Reactor Netty 将停止接受新请求连接,并释放相关资源。
  • 等待宽限期:当前所有活动请求在宽限期内继续处理;在宽限期结束后,未完成的请求将被强制中止。

Reactor Netty 在优雅停机期间通过停止接受新的连接来实现无缝停机。其无阻塞模型让服务在短时间内完成停机。

4. 优雅停机的流程

在 Tomcat 和 Reactor Netty 上的优雅停机流程类似,大致包含以下几个步骤:

  1. 标记服务不可用:停止接收新的请求,通常是通过在负载均衡器中剔除该服务或在网络层阻断连接来实现。
  2. 设置宽限期:当前请求允许在宽限期内继续处理。
  3. 关闭活动连接:宽限期结束后,所有未完成的请求会被中止,资源释放。

Spring Boot 3 的 SmartLifecycleApplicationContext 控制器在关闭阶段对生命周期进行管理,保证所有组件按照顺序优雅停止。

5. 实现优雅停机的完整示例

我们可以创建一个简单的 Spring Boot 3 应用来展示优雅停机配置。

5.1 代码示例

application.yml 中启用优雅停机并设置宽限期为 30 秒:

yaml 复制代码
server:
  shutdown: "graceful" # 开启优雅停机
spring:
  lifecycle:
    timeout-per-shutdown-phase: "30s"  # 停机的宽限期,默认为 30 秒

创建一个简单的 REST 控制器,模拟一个处理时间较长的请求:

java 复制代码
@RestController
@RequestMapping("/api")
public class DemoController {

    @GetMapping("/long-running")
    public String longRunningTask() throws InterruptedException {
        System.out.println("开始执行耗时任务...");
        Thread.sleep(20000); // 模拟耗时任务
        return "任务完成";
    }
}

此控制器会等待 20 秒后返回结果。通过优雅停机机制,即使应用关闭,也会允许该任务在 30 秒宽限期内完成。

启动类里添加一段代码方便打印服务何时停止运行:

java 复制代码
    @PreDestroy
    public void destroy() {
        System.out.println("Application is destroyed");
    }

5.2 IDEA 停止服务

由于 IDEA 运行的服务点击红点结束,会直接停止程序,无法模拟停机,Linux 上通过 java -jar 运行的程序没有这种烦恼,所有此处引入 actuator 的功能,它可以执行 shutdown。

xml 复制代码
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>

增加如下 actuator 配置:

yam 复制代码
management:
  endpoints:
    web:
      exposure:
        include: '*'
  endpoint:
    shutdown:
      enabled: true # 开放停机端口

调用 curl -X POST http://localhost:8080/actuator/shutdown,即可停止服务:

5.3 测试优雅停机

启动应用并访问 http://localhost:8080/api/long-running,然后调用 http://localhost:8080/actuator/shutdown 停止服务。

请求在宽限期内返回 任务完成

修改超期时间为 10s,超过宽限期后,请求被中止。

6. 负载均衡器中的停机策略

在实际应用中,负载均衡器(如 Nginx、Kubernetes)也可以在服务停机时配合优雅停机流程,通过从负载均衡池中剔除当前实例来防止新流量进入。这样可以确保所有请求被其他实例接管,而当前实例只处理已有请求,直至完成后停机。

7. 优雅停机的注意事项

  • 宽限期配置:设置合理的宽限期,确保长时间请求可以完成。
  • 负载均衡器协作:在生产环境中建议与负载均衡器配合,实现完整的优雅停机流程。
  • 避免频繁停机:频繁停机会中断长时间任务,应避免在高负载时频繁重启应用。

8. 总结

在 Spring Boot 3 中,通过简单配置即可实现优雅停机,确保服务在关闭时能够完整处理当前请求,减少对用户体验的影响。在 Tomcat 和 Reactor Netty 上实现的优雅停机过程相似,都采用了在网络层阻止新请求和在应用层设置宽限期的方式。优雅停机机制在高并发服务中显得尤为重要,是微服务架构中保持稳定性和一致性的关键。

相关推荐
阿龟在奔跑42 分钟前
引用类型的局部变量线程安全问题分析——以多线程对方法局部变量List类型对象实例的add、remove操作为例
java·jvm·安全·list
飞滕人生TYF44 分钟前
m个数 生成n个数的所有组合 详解
java·递归
代码小鑫1 小时前
A043-基于Spring Boot的秒杀系统设计与实现
java·开发语言·数据库·spring boot·后端·spring·毕业设计
真心喜欢你吖1 小时前
SpringBoot与MongoDB深度整合及应用案例
java·spring boot·后端·mongodb·spring
激流丶1 小时前
【Kafka 实战】Kafka 如何保证消息的顺序性?
java·后端·kafka
周全全1 小时前
Spring Boot + Vue 基于 RSA 的用户身份认证加密机制实现
java·vue.js·spring boot·安全·php
uzong2 小时前
一个 IDEA 老鸟的 DEBUG 私货之多线程调试
java·后端
AiFlutter2 小时前
Java实现简单的搜索引擎
java·搜索引擎·mybatis
飞升不如收破烂~2 小时前
Spring boot常用注解和作用
java·spring boot·后端
秦老师Q2 小时前
Java基础第九章-Java集合框架(超详细)!!!
java·开发语言