Nginx转发WebSocket断连因未透传Upgrade和Connection头,需配置proxy_set_header Upgrade $http_upgrade、Connection "upgrade"、http_version 1.1、proxy_buffering off及长超时;Go多实例共享状态须用Redis Pub/Sub或Hash,禁用数据库存连接;会话粘性推荐基于cookie或参数哈希;Go中Read/WriteMessage须设超时、用PongHandler防阻塞。

为什么直接用 Nginx 转发 WebSocket 会断连
因为 WebSocket 升级请求(Upgrade: websocket)需要透传,而默认 Nginx 配置会缓存、重写或丢弃 Connection 和 Upgrade 头。不显式放行,后端 Go 服务收不到完整握手,连接在 101 切换阶段就失败。
实操建议:
- 在 Nginx 的
location块中必须添加:proxy_set_header Upgrade $http_upgrade;<br>proxy_set_header Connection "upgrade";<br>proxy_http_version 1.1;
- 禁用
proxy_buffering,避免 WebSocket 帧被缓冲延迟:proxy_buffering off;
- 设置合理超时,防止长连接被中间设备(如云厂商 LB)静默断开:
proxy_read_timeout 86400;<br>proxy_send_timeout 86400;
Go 后端如何支持多实例共享 WebSocket 连接状态
单机内存无法跨进程同步 conn 对象,负载均衡下用户可能被调度到不同实例。若业务需广播、房间管理或状态查询,必须把连接元数据外移到共享存储。
常见方案与取舍:
立即学习“go语言免费学习笔记(深入)”;
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 用 Redis + Pub/Sub 实现消息广播:每个 Go 实例订阅同一 channel,收到消息后只向本机已连接的客户端推送;
redis.PubSub需手动处理重连和消息丢失 - 用 Redis Hash 存连接归属(
user_id → instance_id:port),配合分布式锁做连接注册/注销;注意SETNX和过期时间必须原子执行 - 避免用数据库存实时连接状态——写频次高、延迟不可控,
INSERT/DELETE在万级并发下易成瓶颈
如何让同一个用户的 WebSocket 请求总落在同一台 Go 实例上
不是必须,但能简化状态管理。Nginx 默认轮询不保证粘性,需显式配置。
可行做法:
- 基于请求头做 IP 哈希:
upstream ws_backend {<br> ip_hash;<br> server 10.0.1.10:8080;<br> server 10.0.1.11:8080;<br>}但 NAT 环境下大量用户共用一个出口 IP,会导致严重倾斜 - 更可靠的是基于 Cookie 或 URL 参数哈希:
hash $cookie_ws_route consistent;<br>hash $arg_sid consistent;
前提是前端在首次建连时主动带上唯一标识(如登录后的sid) - 如果用云厂商 SLB(如阿里云 ALB),可开启「会话保持」并指定 Cookie 名称,比 Nginx 更稳定
Go 代码里哪些地方容易触发隐式阻塞导致连接堆积
WebSocket 是长连接,conn.ReadMessage() 和 conn.WriteMessage() 都是阻塞调用。一个 goroutine 卡住,整个连接就卡死,连接数涨上去后新请求排队,最终触发超时或 OOM。
关键避坑点:
- 绝不在
ReadMessage循环里做同步 HTTP 调用或数据库查询;应发消息到 worker channel,由独立 goroutine 处理 - 写操作必须加超时控制:
conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
否则对端断连未及时探测,本机会持续尝试发送,goroutine 泄露 - 用
conn.SetPongHandler()替代手动读Ping,避免漏处理导致连接被误判为失效 - 不要用
time.After做心跳超时,它不随连接关闭自动清理;改用conn.SetReadDeadline()配合ponghandler 更轻量
真实压测中,90% 的“连接数暴涨”问题都出在没设写超时或 Pong 处理缺失。这些细节不报错,但会让系统在流量高峰时无声崩溃。

















