nginx故障转移时websocket中断本质是连接绑定单worker/节点所致,非无感漂移;需隔离location配置proxy_http_version 1.1、upgrade/connection头透传、超时设为86400、禁用buffering与gzip,并为upstream禁用健康检查或定制/healthz端点,配合前端指数退避重连。

WebSocket连接在Nginx故障转移时中断,报错常见为 onclose code 1006、Connection reset by peer 或握手阶段的 Handshake failed,本质不是“切换失败”,而是故障转移过程中连接状态未被正确维持或透传。Nginx本身不原生支持WebSocket连接的“无感漂移”,它不具备会话同步能力,所有连接都绑定在单个worker进程和上游节点上。一旦发生后端节点变更(如upstream健康检查触发摘除)、Nginx主进程重启、或worker热重载,原有TCP连接就会断开——这是正常行为,但可通过配置收敛影响范围。
确认是否真为故障转移引发(而非配置缺陷)
先排除更常见的基础配置问题,它们在故障转移时会被放大,但根源不在切换本身:
- 检查Nginx日志中连接中断时间点是否与
upstream节点状态变更(如health check failed)、reload操作时间完全吻合;若中断随机发生或固定60秒一次,则大概率是proxy_read_timeout或keepalive_timeout未调大所致 - 用
curl -i -H "Connection: Upgrade" -H "Upgrade: websocket" http://your-domain/ws手动模拟握手,观察返回是否为101 Switching Protocols;若返回200/404/502,说明Upgrade头未透传,故障转移前就已不可用 - 抓包验证:在客户端和Nginx之间运行
tcpdump port 80 or port 443,过滤WebSocket路径,看中断前是否有FIN/RST包来自Nginx侧——有则说明Nginx主动断连,非后端切换导致
检查upstream健康检查对WebSocket的干扰
默认的HTTP健康检查会发送普通GET请求,而WebSocket后端若未专门处理该路径,可能返回403/500甚至直接关闭连接,触发误判摘除。更糟的是,某些检查频率过高(如每3秒),会持续冲击长连接:
- 为WebSocket专用location单独定义upstream,并禁用或定制健康检查:
upstream ws_backend {<br> server 10.0.1.10:8080 max_fails=0 fail_timeout=0;<br> server 10.0.1.11:8080 max_fails=0 fail_timeout=0;<br>}
其中max_fails=0关闭自动摘除,靠人工或外部监控干预 - 若必须启用检查,确保检查端点返回200且不干扰业务连接,例如后端暴露
/healthz,并在upstream中配置:health_check interval=30 fails=3 passes=2 uri=/healthz; - 避免使用
slow_start等动态权重策略——WebSocket连接无法在新节点上“继承”,只会加剧重连风暴
验证故障转移期间连接重建逻辑是否健壮
真正的故障转移(如某台后端宕机)必然导致已有连接断开,此时稳定性取决于客户端重连机制与Nginx能否快速接纳新连接:
- 前端必须实现指数退避重连(如1s→2s→4s→8s),而非立即重试,否则在Nginx reload窗口期会触发大量TIME_WAIT和连接拒绝
- Nginx需确保
worker_connections和系统net.core.somaxconn足够支撑瞬时重连洪峰;可临时加日志:log_format ws_debug '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$upstream_addr"';
观察重连高峰时是否出现503 Service Temporarily Unavailable或connect() failed (111: Connection refused) - 后端服务启动时应预留“预热”时间(如延迟注册到服务发现),避免Nginx刚把流量切过去,后端尚未完成WebSocket handler初始化就收到连接请求
关键配置必须隔离到WebSocket专属location块
所有WebSocket相关参数必须写在精确匹配的location /ws/(或你的实际路径)内,不能仅放在http或server块顶层,否则故障转移时可能因配置加载顺序导致部分worker未生效:
- 必需项(缺一不可):
proxy_http_version 1.1;<br>proxy_set_header Upgrade $http_upgrade;<br>proxy_set_header Connection "upgrade";<br>proxy_read_timeout 86400;<br>proxy_send_timeout 86400;<br>proxy_buffering off;<br>gzip off;
- 推荐补充:
proxy_next_upstream error timeout http_502 http_503 http_504;<br>proxy_next_upstream_tries 3;<br>proxy_next_upstream_timeout 10s;
让Nginx在首次连接失败时自动尝试其他节点,减少客户端重连压力 - 禁用
keepalive连接池:proxy_http_version 1.1;已启用HTTP/1.1持久连接,但WebSocket连接本身不走连接池复用,此处keepalive指令对WebSocket无效,无需配置











