Spring Boot优雅停机实战:服务重启不再丢请求,运维高手都在用这招!

凌晨2点,系统突然告警!服务重启导致大量订单请求丢失,用户投诉刷屏……
你是否也遇到过这种“半夜惊魂”?优雅停机正是解决这类问题的金钥匙!
本文将手把手教你用Spring Boot实现零宕机重启,从此告别数据丢失噩梦!


一、什么是优雅停机?

想象一下:餐厅打烊时,服务员不会直接赶走正在吃饭的顾客,而是:
1️⃣ 挂出“停止接单”牌子(拒绝新请求)
2️⃣ 等现有客人吃完结账(处理进行中请求)
3️⃣ 打扫卫生、关闭水电(释放资源)
4️⃣ 锁门下班(安全关闭)

技术版定义
在微服务架构中,优雅停机意味着服务器能够有序地关闭,确保所有正在进行的请求都得到妥善处理,同时不再接受新的请求。

微服务关闭时,先拒绝新流量 → 完成存量请求 → 释放连接/线程 → 安全退出的完整流程。

直接后果

  • 更新版本时用户无感知

  • 金融交易0丢失

  • 运维不用背锅写事故报告


二、Spring Boot优雅停机四重奏

第一重:Actuator秒开优雅停机(适合快速上手)

Step 1:加个“开关”

<!-- pom.xml 加入 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

Step 2:打开停机权限

properties

# application.properties
management.endpoint.shutdown.enabled=true
management.endpoints.web.exposure.include=shutdown

Step 3:优雅关机

curl -X POST http://localhost:8080/actuator/shutdown

注意
⚠️ 一定要上锁!用Spring Security保护接口,否则黑客分分钟让你服务下线!

 

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/actuator/shutdown").hasRole("ADMIN")
            .and().httpBasic();
    }
}


第二重:Tomcat内置优雅停机(Spring Boot 2.3+专属)

配置两行代码直接生效:

# 开启优雅停机 + 30秒超时
server.shutdown=graceful
spring.lifecycle.timeout-per-shutdown-phase=30s

效果

  • 立刻返回Connection: close响应头

  • 等待30秒处理存量请求

  • 超时未完成则强制关闭


第三重:自定义资源清理(高阶必备)

场景

  • 关闭前备份缓存数据

  • 通知注册中心下线服务

  • 等待异步任务完成

代码示例

@Component
public class GracefulShutdownListener implements ApplicationListener<ContextClosedEvent> {
    
    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;
    
    @Override
    public void onApplicationEvent(ContextClosedEvent event) {
        // 1. 停止接收新任务
        taskExecutor.shutdown();
        
        // 2. 等待30秒让现有任务完成
        try {
            if (!taskExecutor.awaitTermination(30, TimeUnit.SECONDS)) {
                taskExecutor.shutdownNow(); // 强制终止
            }
        } catch (InterruptedException e) {
            taskExecutor.shutdownNow();
        }
        
        // 3. 关闭数据库连接池
        HikariDataSource dataSource = ...;
        dataSource.close();
    }
}

第四重:K8s集群部署终极方案

配置模板

apiVersion: apps/v1
kind: Deployment
spec:
  template:
    spec:
      containers:
        - name: springboot-app
          lifecycle:
            preStop: # 关闭前钩子
              exec:
                command: 
                  - "curl"
                  - "-X POST"
                  - "http://localhost:8080/actuator/shutdown"
      terminationGracePeriodSeconds: 60 # 等待1分钟

全流程

  1. K8s发送SIGTERM信号

  2. 执行preStop钩子通知Spring Boot停机

  3. 等待60秒后强制终止(SIGKILL)


三、避坑指南(血泪经验总结)

  1. 线程池必须配置

@Bean(destroyMethod = "shutdown")
public Executor asyncExecutor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setWaitForTasksToCompleteOnShutdown(true); // 关键!
    executor.setAwaitTerminationSeconds(60);
    return executor;
}
  1. 注册中心主动注销

@EventListener(ContextClosedEvent.class)
public void deregisterService() {
    eurekaClient.shutdown(); // Eureka示例
    consulClient.deregister(serviceId); // Consul示例
}
  1. 必须压测验证

  • 用JMeter模拟高并发时突然停机

  • 观察是否有:
    ✅ 新请求立即被拒
    ✅ 存量请求正常响应
    ✅ 日志显示资源释放记录


四、总结

优雅停机三大原则
🔶 快准狠拒绝新流量(负载均衡/网关摘流)
🔶 死等存量请求完成(配置合理超时时间)
🔶 不留任何垃圾数据(连接/线程/文件全释放)

技术选型建议

  • 简单项目 → 直接用Actuator

  • 集群部署 → K8s+preStop组合拳

  • 复杂异步 → 自定义监听器+线程池管理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

呱牛 do IT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值