
滚动发布的目标听起来简单:新版本逐个替换旧版本,全程不中断服务。但实现里藏着两个经典坑:下线时在途请求被掐断(用户看到 502),上线时缓存全空(首批请求全打到数据库)。优雅上下线就是解这两个坑的工程化方案——一个是排空(drain),一个是预热(warmup)。
一个实例从「接流量」到「安全退出」要走三步,缺一步都有故障现场:
第一段:注册中心摘除。实例先从注册中心(Nacos/Consul/K8s Service)反注册。这一步之后,新的请求不再路由到它——但已经建立的健康检查、已发布的客户端本地缓存还没过期,摘除通知传播需要几秒。摘除后必须等待,等多久取决于客户端缓存刷新周期(常见 5~30 秒)。
第二段:网关侧摘除。注册中心之外,负载均衡层(LB/网关)往往有自己的健康检查周期。主动把 LB 的健康检查置为失败(返回 503)或调用 LB 的摘除接口,让 LB 层立刻摘掉它——不等自然健康检查超时。
第三段:等待在途请求完成。摘除只挡新流量,在途的怎么办?等待一个「排空窗口」:sleep 一个大于请求最长处理时间的值(通常取 P999 的 3~5 倍,比如 30 秒),让在途请求自然做完再退出。K8s 里的标准实现是 preStop hook 里 sleep 30,配 terminationGracePeriodSeconds 覆盖。
三段合起来的 K8s 标准配置:preStop 先调摘除接口(或靠 termination 端点自己摘注册),然后 sleep 排空窗口,最后进程退出。
HTTP/1.1 短连接的排空靠「等」就行,长连接(WebSocket/gRPC)不行——连接不会自然结束,「等 30 秒」等不到任何东西,客户端会一直挂在这个实例上直到天荒地老。
长连接的排空要主动驱赶:a. 服务端发 Close 帧(WebSocket 的 close frame / gRPC 的 GOAWAY)通知客户端「我要下了,请重连」;b. 客户端收到 Close 后按重连策略连到别的实例(重连时从注册中心拿最新列表);c. 服务端在 Close 后再等一个窗口(比如 60 秒)处理完在途消息再断 TCP。
没有 a+b 的配合,长连接实例下线就是硬切——客户端突然收到 TCP RST,正在写的消息丢失。所以长连接服务的发布必须实现 GOAWAY 协议,且客户端的重连逻辑要处理「收到 Close 立即重连」。这是很多团队第一次做长连接滚动发布时踩的坑:服务端发了 Close,但客户端没实现重连(或者重连没加退避),发布变成连接风暴。
新实例启动后立刻接全量流量,会经历一个「冷启动恶化期」:JIT 未编译(Java 前几千个请求慢 3~5 倍)、本地缓存全空(缓存穿透打到 DB)、连接池未建立(首批请求排队建连接)。高峰发布时,这个恶化期足以引发 DB 过载——所以预热是发布工程的标配。
预热的三种手段:
流量爬坡:新实例上线时网关权重从 1% 起步,按 1% → 5% → 25% → 100% 的阶梯爬升,每级观察 1~2 分钟。最通用的方案,不依赖应用改造,网关支持就行。
预热请求回放:新实例启动后,先自我加压——用压测流量或录制回放真实请求打自己(QPS 从低到高爬),等 JIT 编译完、缓存填热后再挂到 LB。对 Java 类 JIT 敏感的应用效果显著。
缓存预加载:启动时主动把关键数据加载进本地缓存(从 Redis 拉全量配置、从 DB 拉热点数据),避免线上流量承担冷缓存成本。
生产组合是 a + b/c:流量爬坡保底,预热回放/预加载对性能敏感的服务加配。
手动发布永远会漏步骤——优雅上下线的正确形态是平台化:
发布系统的每一步做成自动检查:摘除后轮询注册中心确认已摘干净(列表里没有该实例)→ 排空窗口计时 → 新版本就绪检查(health endpoint 返回 ready 而不只是 alive)→ 权重爬坡 → 全量。检查不过自动暂停发布并告警,而不是继续滚。
ready 与 alive 的区分是预热的接口基础:alive 表示进程活着,ready 表示「缓存已热、依赖已连、可以接流量」。K8s 的 readinessProbe 探的是 ready——新实例没 ready 之前不会被挂到 Service 后端,这就是平台层的爬坡保障。
回滚也要优雅:回滚是反向的滚动发布,同样需要排空和预热。快速回滚(--record 的版本切换)经常被实现为「硬杀旧起新」,这是发布事故的常见来源——回滚救火时把「优雅」忘了。
怎么知道优雅上下线做对了?三个验收指标:1. 发布期间 5xx 率零上升(在途请求被掐断会表现为 502);2. 发布期间 DB QPS 无毛刺(冷缓存穿透表现为 DB 查询量尖峰);3. 长连接服务的重连率曲线(发布窗口内重连次数 = 被下线的连接数,无 RST 尖峰)。这三个指标接进发布流水线的卡点,每次发布自动验证——优雅上下线就从「最佳实践」变成了「不可回退的工程事实」。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。