Graceful Shutdown 的实践:服务重启不丢请求
2026/7/17 15:17:36 网站建设 项目流程

Graceful Shutdown 的实践:服务重启不丢请求

一、服务重启的「不体面」时刻

独立开发者的部署流程通常是:推送代码,SSH 到服务器,git pull,pm2 restartdocker restart。这个过程看起来流畅,但每一次重启都潜藏着两个问题:正在处理中的请求丢失了,用户看到的是连接错误或 502 页面;正在执行中的异步任务(如文件上传、数据导出)被中断了,并且不知道中断在什么地方

这些问题在用户量少时无关紧要——偶尔几个用户遇到重试几次就好了。但当你的产品有几千个活跃用户、每天处理上万次 AI 调用时,每一次「不体面的重启」都可能造成数十个请求失败、几个异步任务中断、和若干用户的不满。

Graceful Shutdown(优雅关闭)就是解决这个问题——在关闭服务之前,先停止接收新请求,等待正在处理的请求完成,再退出进程

二、HTTP 服务器的 Graceful Shutdown

HTTP 服务器的优雅关闭,需要分三步:

步骤一:停止接收新请求。当进程接收到 SIGTERM 或 SIGINT 信号时,关闭 HTTP 服务器的监听器(server.close()),不再接受新的 TCP 连接。但已经建立的连接,继续处理。

步骤二:给现有请求完成时间。设置一个超时时间(如 30 秒),等待所有活跃的请求处理完成。如果超时后仍有请求未完成,强制关闭连接。

步骤三:关闭依赖资源。请求全部处理完后,按顺序关闭依赖:数据库连接池 → 缓存连接 → 消息队列连接 → 进程退出。

Node.js 的优雅关闭实现:

process.on('SIGTERM', async () => { console.log('Graceful shutdown initiated...'); // 停止接收新请求 server.close(() => { console.log('No longer accepting new requests'); }); // 等待现有请求完成 setTimeout(async () => { await db.disconnect(); await redis.disconnect(); process.exit(0); }, 30000); // 最多等 30 秒 });

三、任务队列 Worker 的优雅关闭

任务队列 Worker 的优雅关闭,比 HTTP 服务器复杂一些——因为任务的处理时间不可预测。一个报表生成任务可能需要 30 秒,一个视频处理任务可能需要几分钟。

Worker 的优雅关闭策略:

  1. 收到关闭信号后,停止从队列中获取新任务。
  2. 等待所有正在执行的任务完成(包括重试中的任务)。
  3. 如果一个任务执行时间超过预设的「最大等待时间」(如 60 秒),标记该任务为「未完成」,让它可以在下一个 Worker 实例上恢复执行。
  4. 所有任务完成后,关闭与队列的连接,退出进程。

关键细节:任务必须是幂等的。因为一个任务可能在 Worker A 上执行了一半被中断,然后在 Worker B 上重新执行。如果任务不是幂等的(如「发送邮件」,发了一半被中断,发送操作已经执行),重新执行会导致邮件重复发送。

四、健康检查与流量切换

优雅关闭不只是应用进程内的事。外部组件(负载均衡器、编排系统如 K8s)也需要配合。

Kubernetes 的配合:在 K8s 中,当 Pod 被终止时,会先收到 SIGTERM 信号,然后有terminationGracePeriodSeconds(默认 30 秒)的时间来优雅关闭。应用需要在preStop钩子或 SIGTERM 处理中完成优雅关闭逻辑。同时,需要配合readinessProbe——应用在收到关闭信号后,readiness 探针应立刻返回「不健康」,让 Service 停止向这个 Pod 发送流量。

Nginx 的配合:如果你用 Nginx 做反向代理,可以通过健康检查让 Nginx 感知到应用实例的关闭。在应用关闭期间,配置一个专门的健康检查端点(如/health),关闭期间返回 503,让 Nginx 停止向该实例分配请求。

五、总结

Graceful Shutdown,核心不是「让关闭变快」,而是让关闭过程「不伤害用户体验」。进程完全可以多活 30 秒,只要这 30 秒内,现有的请求被妥善处理、异步任务被标记为可恢复、外部流量被平滑切走。

对于独立开发者,五个实践要点:(1)在应用中监听 SIGTERM 信号,实现优雅关闭逻辑;(2)关闭期间停止接收新请求,等待现有请求完成;(3)设置最大等待时间(如 30 秒),超过则强制关闭;(4)确保异步任务是幂等的,可以在新实例上重新执行;(5)配合负载均衡器的健康检查,在关闭期间停止接收新流量。

优雅关闭是「在问题发生之前就解决问题」的实践——它不增加任何新功能,只是让已有功能在重启时不中断。用户永远不会知道你在做部署,而这正是优秀产品的体验:部署发生在用户身后,不需要他们感知。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询