qinghuan
← 回到知识探索

后端现场 / 案例拆解

服务要重启,做到一半的请求怎么办?

把停止接单、处理在途请求和到期退出分成三个可观察的阶段。

展开本文目录
  1. 先少接新请求,再处理已经接下的
  2. 应用与平台的时间预算要对得上
  3. 拿一条时间线检验你的设想
  4. 用三类请求观察停机
  5. 记住这三点
  6. 别把例子用过头
  7. 自己试一小步
  8. 查原始资料
  9. 找一份资料继续练
开始前,会这些就够了
  • 知道服务可以有多个实例
  • 知道请求可能需要等待
遇到不熟悉的词,先看这 5 个解释
进程
进程是正在执行的程序及其所需资源形成的运行单位。以常见桌面系统为例,它有自己的地址空间、打开的资源和线程,操作系统据此管理程序的运行。
线程
线程是进程中被安排执行的一条运行路线。同一进程可以有多个线程,共用部分数据和资源,同时各自保存执行位置与调用记录,因此协作时要留意互相影响。
超时
调用方为一次等待设置上限,超过时间还没拿到所需结果,就结束这次等待并报告超时;这样能限制资源占用,但并没有自动确认对方最终做到了哪一步。
负载均衡
在多个可处理请求的后端之间,按轮流、权重或其他规则分配流量,减少请求集中到单个实例的情况;分发依据和健康检查决定实际送给谁。
容器
容器是根据镜像创建的隔离运行环境,用来运行应用进程;镜像带上应用文件和所需依赖,便于重复部署。同一镜像可以创建多个容器,容器也可以处于停止状态。
打开完整术语小抄 ↗

假设订单服务准备发布新版本,旧实例手里还有一个需要数秒才能完成的请求。立刻杀进程可能让客户端只看到断开;一直等所有工作结束,又可能被一个永远不结束的请求拖住。优雅停机是在有限时间里协调收尾,不是承诺任何故障下都零中断。

先少接新请求,再处理已经接下的

可以把流程拆成三阶段:通知入口不要再把常规新请求送来;让已经接下的请求在期限内完成;在平台强制终止之前,预留时间记录未完成状态并退出。实际平台中,摘除流量和应用关闭可能并行发生,不应想象成一个瞬间完成的全局开关。

长连接、代理已经选好的请求以及传播延迟,都可能使停机开始后仍有请求到达。应用要有自己的拒绝新工作规则,入口也要支持连接排空。只把健康检查改成失败,却继续无限接受工作,或只关应用而不考虑入口,都可能在切换时暴露空档。

应用与平台的时间预算要对得上

Spring Boot 3.5 文档说明,优雅关闭给已有请求完成的时间,并限制新请求;每个关闭阶段的等待可通过 spring.lifecycle.timeout-per-shutdown-phase 设置。不同内嵌服务器拒绝新请求的方式不同,不能要求所有框架都返回同一个状态码。

Kubernetes 普通 Pod 终止流程还包含 preStop、终止信号与平台的终止期限。preStop 也消耗这个收尾时间,不能把它当成额外赠送的等待。若平台更早强制终止,应用设置更长的等待也救不了在途请求;预算需要包含必要的退出阶段和余量。

拿一条时间线检验你的设想

假设零秒收到停机通知,一秒时不再接受新业务,原有请求甲在四秒完成,请求乙要到四十秒才完成,而平台在三十秒期限后可能强制结束。甲有机会正常返回;乙不能仅凭“开启优雅停机”就保证完成。这个时间线是设计练习,没有运行真实集群。

乙若已经提交数据库而响应没送达,客户端仍可能面对结果未知。停机策略需要和幂等重试、结果查询相配合。把请求从 HTTP 线程转交后台线程,也不等于它已经可靠保存;进程退出时,只有内存里的任务仍可能消失,必须明确任务归属和持久化时机。

用三类请求观察停机

在自己的测试环境准备短请求、可控慢请求和超时请求,开始停机后检查新请求是否停止接纳、已有请求是否完成、超时任务有没有清楚的结果。测试应使用平台真实的终止方式;某些 IDE 的停止按钮可能立即终止进程,和正常关闭流程不同。

记录接纳时间、业务提交时间、响应完成时间与进程退出时间,再对照客户端看到的结果。后台消费者、定时任务和自建线程池也要有各自的停止规则,不能把 Web 服务器收尾等同于整个应用所有工作均已完成。最后验证超时后的恢复过程,才知道剩余工作会被谁接手。

记住这三点

  • 优雅停机要同时处理新请求、在途请求和退出期限。
  • 应用阶段超时与平台终止期限需要协调,preStop 也占时间。
  • 提交完成但响应丢失仍需幂等与查询机制处理。

别把例子用过头

  • 假设时间线不是集群实测,具体服务器和代理行为需要验证。
  • Web 请求排空不能代表所有后台任务已收尾。
  • 强制终止、机器故障等情况不保证执行普通关闭钩子。

自己试一小步

一个可能运行五分钟的导出任务,如何避免把每次发布都拖五分钟?

  1. 区分请求接纳、任务持久化、任务执行和结果领取四个时刻。
  2. 列出停机发生在各时刻时,用户能查询到的状态。
  3. 提出恢复或重新领取任务的规则,并说明怎样防止重复产物。

做到这些,就算完成

  • 没有把后台线程等同于持久队列。
  • 退出有明确的最长等待预算。
  • 考虑到数据库提交后响应丢失的情况。

查原始资料

想确认一个细节,先看这份资料对应的部分,不必从头读完所有文档。

  • Spring Boot 3.5: Graceful Shutdown (新标签页)↗Spring · 英文

    支持关闭阶段超时、已有请求完成、服务器拒绝方式差异和 IDE 终止信号提示。

    公开英文 3.5 分支文档,内容随补丁更新;关闭行为还取决于所用服务器。

  • Pod 的生命周期 (新标签页)↗Kubernetes · 中文

    直接阅读 Pod 终止流程:preStop、TERM、终止端点状态以及期限后强制结束。

    公开中文文档;本文采用常规终止流程,实验性特性需另外核对 Kubernetes 版本和配置。

找一份资料继续练

先选一项,按下面的范围继续学;不必从头读完整门课程。