
本文是《MCP实战手记系列(十):MCP Server高可用实战》的延伸知识点。完整的高可用方案(多实例、负载均衡、熔断降级、Redis哨兵)见系列(十)。
多实例部署完之后,很多团队以为高可用就做完了。但生产里绝大多数实例下线是运维主动发起的 :发版重启。而事故恢复那套(Nginx把死实例摘掉)管不了这个场景:进程是被主动kill的,Nginx要等请求失败攒够max_fails才知道,那批请求已经变成502了。
也就是说,如果只做故障恢复不做优雅停机,这覆盖的只是那10%的场景,每次发版都会稳定地甩给用户一批错误。
四步流程
摘流量 → 等请求排空 → 停进程 → 部署新版本 → 健康检查通过 → 加回流量
第一步:应用侧开优雅停机。 Spring Boot两行配置:
yaml
server:
shutdown: graceful # 停止接收新请求,等存量请求处理完再退出
spring:
lifecycle:
timeout-per-shutdown-phase: 30s # 最多等30秒,超时强杀
开了之后Tomcat先停止接受新连接,把在途请求处理完才退出。
第二步:Nginx侧摘流量。 最省事的是把该实例在upstream里标成down:
upstream mcp_backend {
server 10.0.0.12:8088 down; # 摘掉,准备发版
...
}
改完nginx -t验一下语法再reload------reload不是重启,但不代表可以跳过校验。
第三步:等排空。 等的时间按最长超时给,一般30秒够。
第四步:滚动发布。 多实例就是这套流程对每个实例轮流做一遍,一次只动一个,保证其他实例一直在接客。
三个坑
坑一:等待时间必须大于最长工具超时。 这条最容易忽略。配了timeout-per-shutdown-phase: 30s,但有个下游调用的超时也是30秒------真有请求卡满30秒时,停机等待同时到期,直接强杀,优雅停机等于没开。要么把下游超时压下去,要么把等待时间加长,两者不能相等。
坑二:健康检查会拖长停机。 应用已经进入shutdown流程了,但/actuator/health可能还返回UP(取决于停机阶段),Nginx还会往里发请求。Spring Boot的readiness探针在停机时会转为DOWN,K8s环境下这一步是自动的;裸机 + Nginx的就得靠主动标down。
坑三:无状态HTTP模式和SSE长连接模式不是一回事。 本文这套在无状态HTTP模式下很干净,没有长连接要drain。如果是SSE长连接,还得处理存量长连接怎么迁移、客户端重连会不会形成风暴------那是另一个问题,本文不覆盖。
小结
优雅停机不是"高级功能",是发布流程的基本配置。四步里最容易漏的是第一步(应用侧配置)和第一、二步之间的配合------只开应用侧配置、不摘流量,Nginx照样在停机窗口里往里发请求。
同专题推荐
本文是「MCP Server高可用」小专题的第2篇,共5篇:
-
- 发版就掉请求?Spring Boot优雅停机的四步(← 当前这篇)
-
- 超时不是一个数字,是一套体系:MCP Server的五条约束(待发)
-
- 高可用配完之后:该看哪几个指标,池子该设多大(待发)
-
- 缓存穿透、击穿、雪崩:三个概念,三种解法(待发)
相关阅读