Nginx reload 导致 WebSocket 断连的本质是旧 worker 进程强制终止长连接,需通过 worker_shutdown_timeout、stream 模块透传或后端状态外置实现平滑过渡。

Reload Nginx 时 WebSocket 连接大面积断连,本质不是“重连失败”,而是连接被强制中断——Nginx reload 默认会关闭所有现存连接(包括已升级的 WebSocket),导致客户端瞬间失联。这不是前端重连逻辑能解决的问题,必须从 Nginx 的进程模型和连接管理机制入手优化。
理解 reload 的真实行为
Nginx reload 并非热更新:它启动新 worker 进程,但旧 worker 进程在处理完当前请求后会退出;而 WebSocket 是长连接,不属“请求-响应”范畴,旧 worker 不会等待其自然关闭,而是直接终止 TCP 连接。客户端收到 FIN/RST 包,触发 onclose,此时无论前端重连多快,都已产生业务中断。
启用 graceful shutdown 与连接平滑过渡
让旧 worker 在退出前继续服务已有 WebSocket 连接,直到连接自然关闭或超时:
- 在 nginx.conf 的 http 或 stream 块中添加:
worker_shutdown_timeout 60s; —— 允许旧 worker 最多再运行 60 秒,期间持续处理活跃连接 - 确保 upstream 配置启用 keepalive:
upstream ws_backend {
server 127.0.0.1:8080;
keepalive 32;
} - 配合 proxy_http_version 1.1 和 upgrade 头透传,使连接真正复用底层 TCP 连接池,减少 reload 时的连接重建压力
启用 nginx-stream-module 处理 WebSocket(推荐)
HTTP 模块对长连接 reload 支持有限;stream 模块工作在 TCP 层,天然支持连接透传,reload 时不会干扰已建立的 WebSocket 流:
- 确认已编译或加载 nginx-stream-module(主流发行版默认包含)
- 在 nginx.conf 中新增 stream 块(非 http 块):
stream {
upstream ws_stream {
server 127.0.0.1:8080;
}
server {
listen 8081;
proxy_pass ws_stream;
proxy_timeout 86400;
proxy_responses 1;
}
} - 前端连接地址改为
ws://your-domain.com:8081/xxx,绕过 HTTP 层代理,彻底规避 upgrade 头丢失与 reload 断连问题
配合后端实现连接状态可迁移(高阶)
即使 Nginx 层优化到位,单点故障仍可能引发批量断连。建议后端引入连接状态外部化:
- 将用户连接 ID、会话状态、最后消息 ID 写入 Redis 等共享存储
- reload 后,客户端重连时携带上次连接 ID,后端快速恢复上下文,避免重复登录或消息丢失
- 结合 Nginx 的 proxy_next_upstream error timeout,当某 backend 实例不可达时自动切到健康节点,进一步降低 reload 影响面


















