零停机平滑重启需nginx与node.js协同实现:nginx通过upstream+reload保持转发不中断,node.js通过sigterm优雅退出+健康检查确保请求不丢失,配合pm2 reload完成“先启新、再切流、后停旧”流程。

Nginx 本身不直接部署 Node.js 应用,而是作为反向代理将请求转发给后端 Node.js 进程(如通过 proxy_pass http://127.0.0.1:3000)。因此,“Node.js 部署的零停机平滑重启”本质是 Nginx + Node.js 协同实现的服务无中断更新,关键在于:Nginx 不中断转发,Node.js 进程不丢请求。两者需各自做好平滑动作,再配合完成整体零停机。
✅ Nginx 层:确保代理链路持续可用
Nginx 的作用是稳定入口,它本身必须支持配置热重载,且不能因 Node.js 后端切换而报错(如 502 Bad Gateway)。
-
配置健壮性
- 使用
upstream定义多个 Node.js 实例(即使当前只启一个),便于未来横向扩展或滚动更新:upstream node_backend { server 127.0.0.1:3000 max_fails=3 fail_timeout=30s; # 可预留 3001、3002 等端口,为多实例/蓝绿部署留余地 } - 开启健康检查(需商业版)或配合简单探针(如
/healthz路由)+ 自动剔除机制(可通过nginx-plus或外部工具如 Consul 实现);开源版可借助proxy_next_upstream error timeout http_502提升容错。
- 使用
-
Nginx 配置变更时零中断
- 修改
upstream或proxy_pass地址后,执行nginx -s reload:- 主进程校验语法 → 成功则 fork 新 worker → 旧 worker 继续处理已建立连接 → 新 worker 接管新连接。
- 只要 Node.js 服务在 reload 前后始终有至少一个健康实例监听对应端口,用户完全无感知。
- 修改
✅ Node.js 层:应用自身支持平滑启动与退出
这是真正决定“是否丢请求”的核心。不能靠 kill -9 或简单 pm2 restart,必须让 Node.js 进程优雅关闭。
-
监听 SIGTERM 信号,延迟退出
在主进程中捕获信号,停止接受新连接,并等待已有请求完成:const server = http.createServer(handler); process.on('SIGTERM', () => { console.log('SIGTERM received, closing server...'); server.close(() => { console.log('HTTP server closed'); process.exit(0); }); // 可选:设置超时强制退出,防卡死 setTimeout(() => process.exit(1), 30000); }); server.listen(3000); -
使用进程管理器支持 graceful reload
-
PM2(推荐):启用内置集群与 graceful reload
# 启动时指定 graceful 选项 pm2 start app.js --name myapp --watch --max-memory-restart 200M # 零停机更新(自动逐个重启 worker,保持至少一个在线) pm2 reload myapp
✅
pm2 reload会:启动新实例 → 等待其 ready → 发送SIGTERM给旧实例 → 旧实例优雅退出 → 全程不中断响应。 Cluster 模式(原生):主进程 fork 多个 worker,主进程监听
SIGUSR2触发 worker 滚动重启,配合worker.disconnect()实现平滑。
-
-
健康检查端点(必备)
添加/healthz路由,返回200 OK仅当:- 服务已启动;
- 数据库连接就绪;
- 内部队列空或可控。
Nginx 可结合此接口做上游可用性判断(需配合外部健康探测脚本或 nginx-plus)。
✅ 协同关键:部署流程设计
单次升级应遵循「先启新、再切流、后停旧」逻辑:
-
步骤示意(以 PM2 + 单实例为例)
- 将新代码推送到服务器,安装依赖;
- 执行
pm2 reload myapp—— 新进程启动并监听3000,旧进程开始优雅退出; - Nginx 无需任何操作(仍 proxy_pass 到
3000),因端口复用且连接未断; - 旧进程处理完最后请求后自动退出,整个过程对客户端透明。
-
进阶方案(蓝绿/金丝雀)
- 启动新版本到
3001端口,用 Nginxupstream动态切换权重或修改proxy_pass指向; - 配合
nginx -s reload切换流量,再安全停掉旧端口进程; - 需注意:确保两个 Node.js 实例不共用同一数据库连接池或共享状态,避免竞态。
- 启动新版本到
Nginx 是可靠的反向代理守门人,Node.js 是实际处理请求的业务单元。零停机不是靠某一个组件单独完成,而是靠 Nginx 的 reload 机制 + Node.js 的信号感知 + 进程管理器的滚动策略三者严丝合缝配合。只要 Node.js 能正确响应 SIGTERM 并完成现有请求,Nginx 能持续转发不报错,升级就真的可以做到用户毫无察觉。











