资讯动态

Express 应用的健康检查与优雅关闭:从 SIGTERM 到 Kubernetes 探针的可靠部署实践

发布时间:2026/10/13 7:41:46 来源:尧图企业网站定制
文档教程技术博客【免费下载链接】expressjs.comThe Express.js Website项目地址https://gitcode.com/gh_mirrors/ex/expressjs.com点击查看免费下载本篇指南以 expressjs.com 仓库 中的「健康检查与优雅关闭」文档为主体系统讲解在 Express 应用中实现优雅关闭Graceful Shutdown与健康检查Health Check的完整方案如何正确处理SIGTERM信号完成请求收尾与资源清理如何实现liveness/readiness探针端点并与 Kubernetes 等负载均衡器协同从而让每次发版、重启都做到零中断、零请求丢失。读完本篇你将掌握一套可直接复制到生产项目中的可靠部署闭环。优雅关闭为什么发版前必须先「关门」部署应用新版本时必须替换旧版本。无论你使用的是 PM2、systemd 还是 Kubernetes 滚动更新进程管理器都会先向应用发送SIGTERM信号通知应用「你即将被终止」。应用收到该信号后正确的行为不是立刻退出而是依次完成以下四步停止接收新请求——不再接受新的连接与新的 HTTP 请求完成所有正在处理的请求——让已进入事件循环的在途请求自然结束释放已使用的资源——包括数据库连接、文件锁等外部资源退出进程。如果应用忽略SIGTERM或直接强杀进程正在处理中的请求会突然中断数据库事务可能处于半提交状态文件锁可能残留最终造成数据不一致。这就是「优雅关闭」存在的意义。官方最小示例原文档给出了一个最精简的优雅关闭实现const server app.listen(port); process.on(SIGTERM, () { debug(SIGTERM signal received: closing HTTP server); server.close(() { debug(HTTP server closed); }); });这个示例的核心是两点保存app.listen()返回的server引用以及在SIGTERM中调用server.close()。从源码看server.close()与app.listen()的关系为什么示例必须把app.listen(port)的返回值存下来查阅 Express 5.x API 参考application 部分 可以找到依据app.listen()返回一个http.Server对象对于 HTTP它本质上是以下代码的便捷封装app.listen function () { const server http.createServer(this); return server.listen.apply(server, arguments); };也就是说express()返回的app本身只是一个 JavaScriptFunction被当作回调传给 Node 的 HTTP 服务器server.close()是 Node 原生http.Server的方法用于停止接收新连接并等待所有已建立的连接处理完毕后再触发回调。此外API 参考还强调了几点与部署直接相关的细节port省略或为0时操作系统会自动分配一个未使用的随机端口——这常被用于自动化任务如测试支持 UNIX socket 路径监听app.listen(/tmp/sock)服务器触发error事件如EADDRINUSE端口被占用时错误会传给callback应在回调内处理const server app.listen(8080, 0.0.0.0, (error) { if (error) { throw error; // e.g. EADDRINUSE } console.log(Listening on ${JSON.stringify(server.address())}); });这些能力意味着你可以用同一套server.close()逻辑管理 TCP 端口与 UNIX socket 两种监听形态的实例。生产级完整实现超时兜底 资源清理官方最小示例只处理了 HTTP 服务器本身生产环境通常还需要补充两件事资源清理在server.close()回调里关闭数据库连接池、释放文件锁超时兜底如果存在长连接如 WebSocket、流式响应server.close()可能迟迟无法完成需要设定一个宽限期超时后强制退出避免进程被挂起。一个更完整的参考实现const server app.listen(port); const SHUTDOWN_TIMEOUT 10000; // 10 秒宽限期 function shutdown(signal) { debug(${signal} signal received: closing HTTP server); // 1. 停止接收新连接等待在途请求完成 server.close(() { debug(HTTP server closed); // 2. 清理外部资源数据库连接、文件锁等 db.end().then(() { debug(Database connections closed); process.exit(0); }); }); // 3. 超时兜底宽限期后强制退出 setTimeout(() { debug(Forcing shutdown after timeout); process.exit(1); }, SHUTDOWN_TIMEOUT).unref(); } // 进程管理器PM2/systemd/Kubernetes在终止前发送 SIGTERM // CtrlC 场景下终端会发送 SIGINT同样值得处理 process.on(SIGTERM, () shutdown(SIGTERM)); process.on(SIGINT, () shutdown(SIGINT));几点实践说明setTimeout(...).unref()让定时器不阻塞事件循环的自然退出仅在服务器迟迟未关闭时兜底触发数据库连接池如mysql/pg的连接池应在服务器关闭后统一end()避免进程退出时残留未归还的连接强制退出使用非零退出码1便于进程管理器识别异常并触发告警。反模式提醒不要靠uncaughtException续命在部署与关闭流程中一个常见的错误想法是「监听uncaughtException让进程继续运行」。官方 性能最佳实践文档 明确警告监听uncaughtException会改变进程的默认行为——异常发生后进程继续运行但此时进程状态已不可靠、不可预测继续运行是危险且不推荐的。Node 官方也将其认定为粗劣做法。官方推荐的方式正是多进程 进程管理器崩溃后重启通常是从错误中恢复的最可靠方式。这一原则与优雅关闭一脉相承把「状态不确定的进程」交给重启机制去处理而不是试图在不确定状态下挣扎存活。健康检查让负载均衡器知道实例「活没活、能不能接客」负载均衡器通过健康检查判定应用实例是否健康、能否接收请求。以 Kubernetes 为例原文档明确引用它提供两类探针probeliveness存活检查决定何时重启容器。它回答的是「进程是否还活着」——如果存活检查失败Kubernetes 会杀掉容器并按重启策略重建readiness就绪检查决定容器何时准备好开始接收流量。它回答的是「能否接客」——当 Pod 未就绪时会从 Service 的负载均衡器中被剔除不再转发流量给它。两者的分工是优雅关闭在平台层面的镜像readiness负责在流量进入前把关liveness负责在进程死亡后兜底二者缺一不可。在 Express 中实现健康检查端点实现方式很简单用app.get()暴露一个或多个 HTTP 端点即可。参考 API 参考中app.get()的用法// 存活检查进程能响应即视为存活 app.get(/healthz, (req, res) { res.status(200).send(ok); }); // 就绪检查除进程存活外还要验证关键依赖可用 app.get(/readyz, async (req, res) { try { await db.query(SELECT 1); // 验证数据库连接池可用 res.status(200).json({ status: ready }); } catch (err) { res.status(503).json({ status: not ready }); // 503 通知负载均衡器剔除 } });要点liveness端点保持轻量——只检查进程能响应 HTTP 即可不要做数据库查询等可能引入延迟或连锁失败的操作否则一次数据库抖动会触发整批容器重启readiness端点可以做依赖检查——数据库、缓存、第三方服务不可用时返回503负载均衡器据此将实例摘除而不是让它带着不可用的依赖继续接收流量返回503 Service Unavailable是健康检查失败的惯例Kubernetes 与绝大多数负载均衡器都以此判定「未就绪」。与 Kubernetes 探针配置的对应关系将上述端点接入 Kubernetes 的典型配置如下httpGet探针直接请求 Pod 内端口上的 HTTP 路径# deployment.yaml示意 spec: containers: - name: app ports: - containerPort: 3000 livenessProbe: httpGet: path: /healthz port: 3000 initialDelaySeconds: 5 periodSeconds: 10 readinessProbe: httpGet: path: /readyz port: 3000 initialDelaySeconds: 5 periodSeconds: 5这里的path与 Express 路由一一对应/healthz对应存活端点/readyz对应就绪端点。Pod 就绪前Kubernetes 不会把流量路由给它就绪探针连续失败后Pod 会被从 Service 端点列表中剔除。部署闭环优雅关闭与探针如何协同把两部分合在一起一次滚动更新的完整时序是新版本 Pod 启动readinessProbe先探活返回 200 后才被加入 Service 负载均衡开始接收流量旧版本 Pod 收到SIGTERM——此时它应先把 readiness 端点切换为 503或依赖平台自动摘除让负载均衡器停止向其转发新流量server.close()停止接收新连接等待在途请求完成清理数据库连接、文件锁等资源后正常退出若在宽限期内未完成超时兜底强制退出由livenessProbe与重启策略接管。其中第 2 步是实现「零中断」的关键如果旧 Pod 直接关闭端口而不先摘除流量负载均衡器仍可能在摘除生效前把新请求转发过来造成连接中断。相关文档与源码索引英文源文档healthcheck-graceful-shutdown.mdx本仓库 10 种语言均有同主题翻译中文版见 zh-cn 版本该页面在官方导航中的登记位置docs 菜单配置标记为global: true属于不区分版本的全局页面app.listen()的完整 API 与底层http.createServer封装application API 参考app.get()路由的签名与用法application API 参考进程异常处理的反模式警示性能最佳实践内容集合的组织方式与「全局页面」规则docs/content.md赞分享文档教程技术博客【免费下载链接】expressjs.comThe Express.js Website项目地址https://gitcode.com/gh_mirrors/ex/expressjs.com点击查看免费下载相关推荐Ory Hydra容器健康检查Kubernetes就绪探针配置实践Ory Hydra容器健康检查Kubernetes就绪探针配置实践 在云原生环境中容器健康检查是保障服务稳定性的关键机制。本文将详细介绍如何为Ory Hyd认证鉴权后端直连建不起来、通话频繁掉线用 Cloudflare TURN 补齐 8 个生产级坑点的实战指南直连建不起来、通话频繁掉线用 Cloudflare TURN 补齐 8 个生产级坑点的实战指南 WebRTC 直连被 NAT 挡住的场景用 Cloudfla人工智能AI 技能AI 插件solidtime服务健康检查Kubernetes liveness探针配置solidtime服务健康检查Kubernetes liveness探针配置 服务可用性痛点与解决方案 生产环境中solidtime作为时间跟踪系统需保证9后端前端企业应用上一篇Computer-Science-Papers-For-System-Design必读论文TOP10架构师推荐的经典文献清单下一篇Radicale完整指南轻松搭建个人自托管日历同步服务器创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑