给云上应用加上健康检查与优雅停机:一次滚动发布丢请求的复盘
一次凌晨的滚动发布,监控图上出现了一小段请求失败的毛刺。总量不大,时间也不长,但足以让值班的人睡不着:发布按批次进行,旧实例还没全部下线,新实例已经开始接流量,中间那几秒,恰好有请求落到了正在退出的实例上。这次复盘不谈某一家厂商的某个开关,只谈发布时必须同时成立的三个条件。
当时发生了什么
那次只是一次常规的接口优化,策略是逐台替换:先起新实例,确认能跑起来,再停旧实例。问题出在两个细节上。第一,新实例端口刚监听就被判定为可用,实际上缓存还没预热、连接池还没建好,第一个请求进来就慢了半拍。第二,旧实例收到停止信号后立刻退出,正在处理的请求没有被排空,负载均衡还以为它活着,又把新请求分了过去。
为什么会丢请求
第一是就绪判断。进程能启动不等于能对外服务。只看端口通不通的检查,会把还没准备好的实例放进流量池。正确的做法是留一个就绪接口,比如 /health/ready,只有依赖就绪、关键初始化完成才返回成功。
第二是流量摘除的时序。停实例之前,要先让它从后端列表里摘掉,并等一小段时间,让在途请求自然结束。这个等待时间要大于客户端的超时和重试间隔,否则摘除本身也会制造失败。
第三是优雅停机。收到停止信号后,应先停止接受新请求,再等正在处理的请求完成或达到宽限时间,最后才退出。宽限时间要看接口的 P99 耗时,留出两到三倍余量;数据库连接、消息消费等有状态环节,也要在停机流程里有序关闭。
落地清单
首先,把存活检查和就绪检查分开。存活检查回答进程是不是还活着,就绪检查回答能不能接新流量,两者混用会让就绪失败时反复重启进程。
其次,发布坚持先扩后缩。先加新实例,等就绪检查连续通过、错误率和延迟回到基线,再逐步摘掉旧实例。一次只动一小批,观察一轮再动下一批,出了问题立刻停手。
再次,把停机流程写进部署脚本,而不是依赖人工记得操作。停止信号、排空等待、宽限超时三个参数要显式配置,并写进运维文档。
最后,发布期间盯着三张图:成功率、延迟分位数和实例数。任何一个信号异常,都先暂停发布再定位原因;事后把毛刺时间点和发布批次对齐,往往一眼就能看出是哪一批出了问题。
怎样验证
最直接的办法是在测试环境做一次有流量的发布演练:持续发请求的同时执行滚动发布,统计窗口内的失败数和最大延迟。第一次演练很可能还会发现问题,比如排空时间太短,或某个长接口的超时比宽限时间还长,调到合理值再跑一次,直到窗口内零失败才算通过。
结语
滚动发布丢请求,往往不是某次改动写错了,而是流程里少了一道防护。健康检查管新实例能不能接流量,流量摘除管旧实例何时退出视野,优雅停机管进行中的请求能不能善终。三件事都做到位,发布就能从提心吊胆的操作,变成按部就班的常规动作。
- 点赞
- 收藏
- 关注作者
评论(0)