资讯动态

K8S滚动升级,SpringBoot优雅停机

发布时间:2026/9/29 4:21:55 来源:尧图企业网站定制
需求在K8S服务滚动升级时Springboot服务可能不可用或者服务数据未处理完形成脏数据。如何处理1、K8s配置新服务启动完成后再关闭旧服务。2、Tomcat启用优雅停机配置停机不再接收新的请求等待已有请求完成。3、Springboot内部收到停机消息等待现有的线程池、队列等任务完成后再停机。1. 机制背景与痛点1.1 原生 Spring 停机缺陷K8s 滚动升级、Pod 重建时容器会收到SIGTERM关闭信号。SpringBoot 原生停机逻辑存在明显短板触发关闭后会立即执行各类 Bean 的PreDestroy销毁方法直接关闭自定义线程池、消息消费容器、连接池等资源正在执行的长任务、异步消息任务会被强制硬砍导致数据不完整、任务中断、业务异常1.2 分层优雅停机设计本通用机制将停机能力分层各司其职全覆盖业务场景Web 层原生能力server.shutdown: graceful停止接收新 HTTP 请求等待存量 HTTP 请求执行完毕业务层自研通用能力接管自定义线程池、消息消费者等异步任务实现「停止新任务 等待存量任务跑完」补齐 Spring 原生短板所有停机流程均受 K8sterminationGracePeriodSeconds超时约束避免容器被强制杀死。2. 核心组件架构通用可复用整套框架无业务侵入纯基础设施组件所有 Bean 统一通过配置类装配规避重复注册、启动异常问题。核心组件核心职责TaskSource通用任务源接口定义所有需要优雅停机的任务契约统一规范任务停止、计数能力GracefulShutdownCoordinator任务源注册中心 核心等待器纯 POJO 无第三方依赖负责统一调度所有任务源停机、等待任务静默GracefulShutdownListenerSpring 关闭事件监听器最高优先级执行保障停机时序正确性埋点监控指标InFlightCounter线程池精准在途任务计数器替代原生近似计数杜绝任务漏统计TaskSourceRegistrationVerifier启动校验器校验所有预期任务源是否正常注册提前暴露配置/代码遗漏问题GracefulShutdownEndpointActuator 监控端点暴露实时在途任务快照用于线上排查问题GracefulShutdownConfig唯一装配入口统一注册所有停机组件禁止组件自行实例化2.1 核心设计理念职责解耦协调器负责核心静默等待逻辑监听器负责时序控制、指标埋点保证核心逻辑可独立单元测试统一装配所有组件不使用Component自动注册统一由配置类Bean注入避免同名 Bean 冲突高容错性单个任务源异常不影响整体停机流程宁可多等、绝不提前放行2.2 TaskSource 通用契约核心规范所有需要纳入优雅停机管理的任务源线程池、消息消费者等必须实现该通用接口保证行为统一// 获取任务源唯一名称用于日志、监控、配置匹配 String name(); // 获取当前正在执行的在途任务数精准计数禁止估算 int inFlightCount(); // 停止接收新任务幂等设计可重复调用 void stopAcceptingNewWork();关键约束禁止使用原生线程池估算计数getActiveCount() 队列大小原生方法为近似值精度不足针对CallerRunsPolicy拒绝策略任务会在调用方线程执行原生计数完全遗漏导致停机误判任务为空、提前关闭统一使用InFlightCounter装饰器任务提交计数 1任务结束 finally 计数 -1全覆盖execute/submit所有提交方式适配 MDC 透传、各类拒绝策略。3. 任务源注册与启动校验3.1 通用任务源类型框架支持两类通用任务源接入覆盖绝大多数业务场景自定义业务线程池通过InFlightCounter精准统计在途任务依靠队列自然排空任务消息消费容器Redis Stream/RabbitMQ/Kafka停止拉取新消息等待存量消费任务执行完毕3.2 启动防漏校验机制通过配置项graceful.shutdown.expected-sources配置预期需要注册的任务源清单应用启动完成后自动对比「配置预期清单」和「实际注册任务源」存在缺失任务源则打印 ERROR 日志提前暴露注册遗漏、命名不匹配问题仅告警不阻断启动兼顾稳定性与可观测性支持配置占位符避免硬编码导致的命名不一致问题4. 完整优雅停机执行流程4.1 整体时序图K8s 下发 SIGTERM 信号 → Spring 触发容器关闭 → 优先执行自定义优雅停机逻辑 → 最后执行原生 Bean 销毁K8s 滚动升级 / Pod 销毁SIGTERM │ ▼ Spring 容器启动 doClose() 关闭流程 │ ├── [阶段1前置优雅停机核心自定义逻辑] │ │ │ ▼ │ 触发 ContextClosedEvent 容器关闭事件 │ │ │ ▼ │ GracefulShutdownListener最高优先级优先执行 │ 1. 记录停机触发监控指标 │ 2. 调用协调器执行任务静默等待 │ │ │ ▼ │ ① 遍历所有已注册任务源批量停止接收新任务 │ ② 每100ms轮询所有任务源在途任务数 │ - 全部为0立即结束等待进入销毁阶段 │ - 超时未清零打印告警日志列出阻塞任务源强制放行 │ - 计数异常标记为非空闲持续等待容错优先 │ ▼ └── [阶段2原生Bean销毁流程] 执行所有 PreDestroy 方法 关闭线程池、消息容器、连接池等资源4.2 核心容错策略异常容错单个任务源停止失败、计数异常不中断整体停机流程仅打印告警超时兜底超过最大等待时间后强制放行避免 Pod 卡死无法销毁宁可多等、绝不早放计数异常默认判定为有任务在途持续等待杜绝任务被硬砍5. 监控与可观测能力5.1 核心监控指标可配置告警框架内置 Micrometer 指标无缝对接 Prometheus/Grafana生产必配告警指标名称类型监控意义graceful.shutdown.triggered计数器优雅停机触发总次数统计滚动升级、重建频次graceful.shutdown.wait计时器每次停机等待耗时用于评估任务积压情况graceful.shutdown.timeout计数器核心告警指标停机超时次数非 0 即代表存在任务堆积中断风险graceful.shutdown.source.timeout标签计数器按任务源维度统计超时次数精准定位阻塞任务类型5.2 在线排查端点暴露 Actuator 自定义端点实时查询任务状态GET /actuator/gracefulshutdown返回所有任务源名称、实时在途任务数-1代表任务计数异常可快速排查线上任务积压、注册异常问题。6. 关键配置与 K8s 对齐规范6.1 应用核心配置通用 yml# Web层优雅停机原生 server: shutdown: graceful 自定义业务层优雅停机 graceful: shutdown: # 最大任务等待超时根据业务长任务耗时调整 max-wait: 4m # 预期需要注册的所有任务源清单启动校验 expected-sources: - customTaskExecutor - stream-consumer-1 - stream-consumer-2 全局异步线程池兜底等待 spring: task: execution: shutdown: await-termination-period: 240s6.2 K8s 配置强制对齐规则核心原则K8s 容器优雅停机超时时间必须大于应用所有等待时长总和预留缓冲时间避免被 SIGKILL 强制截断。通用 K8s Deployment 核心配置spec: # 容器整体优雅停机超时必须大于应用max-wait建议预留30-60s缓冲 terminationGracePeriodSeconds: 300 strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 # 滚动升级最大超量Pod maxUnavailable: 0 # 禁止同时销毁Pod保证流量无损 template: spec: containers: - name: service-name # 探针适配长任务服务避免压测/高峰期误杀Pod readinessProbe: httpGet: path: /actuator/health/readiness port: 8080 initialDelaySeconds: 30 periodSeconds: 5 timeoutSeconds: 8 failureThreshold: 3 livenessProbe: httpGet: path: /actuator/health/liveness port: 8080 initialDelaySeconds: 60 periodSeconds: 10 timeoutSeconds: 8 failureThreshold: 56.3 配置动态刷新能力graceful.shutdown.max-wait支持 Nacos 动态刷新无需重启服务下次停机自动生效graceful.shutdown.expected-sources仅启动时加载修改后需重启属于固定组件配置线程池本地等待时长启动固化不支持动态刷新7. 核心设计约束与最佳实践7.1 时序绝对约束优雅停机监听器必须设置最高执行优先级Spring 关闭时序先广播ContextClosedEvent→ 后执行PreDestroy若优先级过低线程池、消息容器会先被销毁导致停机等待逻辑空转任务直接被硬砍7.2 任务接入最佳实践必接入场景所有耗时 1s 的长任务、异步消息消费、定时任务无需接入场景可重跑、无状态、低优先级的后台任务避免过长占用升级窗口计数规范统一使用InFlightCounter禁止原生线程池近似计数命名规范任务源名称全局唯一与配置清单严格一致避免覆盖注册7.3 线上运维规范监控graceful.shutdown.timeout指标出现非 0 值立即排查任务阻塞问题修改任何停机等待时长必须同步修改 K8sterminationGracePeriodSeconds新增业务线程池/消息消费者必须同步注册 TaskSource 并加入预期配置清单8. 总结本通用优雅停机框架补齐了 SpringBoot 原生停机能力的短板实现了HTTP 请求 自定义线程池 消息消费任务的全覆盖优雅停机。通过标准化任务契约、启动防漏校验、全维度监控、K8s 时序对齐彻底解决了容器滚动升级时长任务被强制中断的问题。整套架构无业务侵入、可复用性极强可作为公司 Java 微服务统一优雅停机基础设施适配所有 K8s 部署的 SpringBoot 项目。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑