websocket并发卡在1k主因是bridge模式下nf_conntrack表满、iptables nat开销大及ulimit与somaxconn未同步调优;改用host模式可绕过conntrack并直用宿主机参数,实测支持50w+连接。

容器跑 WebSocket 时并发上不去,八成不是代码问题,而是 Docker 网络模式 + ulimit + 内核参数三者没对齐。
为什么 bridge 网络下 WebSocket 连接数卡在 1k 左右
bridge 是 Docker 默认网络,但它对长连接有两层隐性限制:
- 每个容器共享宿主机的
nf_conntrack表,默认大小通常只有 65536,大量短生命周期 WebSocket 握手(尤其带 TLS)会快速填满,触发nf_conntrack: table full, dropping packet - bridge 模式经过 iptables NAT,所有连接都要走 conntrack,而
net.netfilter.nf_conntrack_max未调大时,新连接会被静默丢弃,客户端表现为“连接超时”或“握手失败”,日志里却找不到明显错误 - 容器内
ulimit -n设到 65536 也没用——如果宿主机net.core.somaxconn还是 128,accept()队列一满,新连接根本进不来
host 网络模式真能突破连接瓶颈吗
能,但代价明确:放弃网络隔离,容器直接复用宿主机网络栈。这意味着:
- 无需 conntrack 跟踪,
net.ipv4.tcp_max_syn_backlog和net.core.somaxconn直接生效,实测单机可稳上 50w+ 连接(Go + host + 调优后) - 端口冲突风险高:多个容器不能同时监听 80 或 443;调试时
ss -tuln看到的是宿主机全局端口,排查更难 - Docker Compose 中必须显式写
network_mode: host,且ports字段失效,不能再用-p 8080:80映射 - 安全审计常拒批 host 模式,尤其金融、政企环境
WebSocket 客户端连不上?先查 Nginx 代理头和 Docker DNS
90% 的“连接返回 200”问题,根因不在应用层,而在两处:
- Nginx 配置漏了关键三行:
proxy_http_version 1.1、proxy_set_header Upgrade $http_upgrade、proxy_set_header Connection "upgrade"。少任意一个,WebSocket 握手就降级成 HTTP,后端收不到Upgrade: websocket头 - Docker 容器默认用
8.8.8.8做 DNS,但某些私有证书或内部域名解析失败,导致 TLS 握手卡在 DNS 查询。可在docker run加--dns 10.0.0.1,或在docker-compose.yml的 service 下加dns: [10.0.0.1] - 若用自签名证书,客户端(如浏览器)可能因证书不被信任而中断连接,此时服务端日志无异常,但
openssl s_client -connect host:443 -servername example.com可验证 TLS 层是否通
Swarm 或 Kubernetes 部署 WebSocket 必须绕开的坑
Swarm 内置的 overlay 网络和 VIP 负载均衡器对长连接支持极弱:
- Swarm 的 ingress 网络会定期重置空闲连接,即使你设了
proxy_read_timeout 86400,连接也可能在 30 分钟后断开,现象是客户端收到onclose但无 error - Kubernetes Service 默认是 iptables 模式,每新增 1w 条规则性能下降明显;改用
ipvs模式并配sessionAffinity: ClientIP才能保连接粘滞 - 健康检查别用 HTTP 探针:WebSocket 服务没有
/healthz端点,强行加会误杀存活连接。应改用exec探针,执行ss -tn state established '( dport = :8080 )' | wc -l判断连接数是否 > 0
真正卡住 WebSocket 并发上限的,从来不是语言或框架,而是容器网络模式与系统参数之间那几行没配对的 sysctl 和 ulimit。调参时别只盯着容器里,ss -s 和 dmesg | grep -i "conntrack\|syn" 才是真相入口。











