单机 websocket 并发突破 1k–5k 需调优系统资源、nginx 配置和服务端事件模型:修改文件描述符限制、内核参数;nginx 显式透传 upgrade 头并关闭缓冲;选用高效事件循环(如 libevent)并匹配心跳与超时。

单机 WebSocket 并发连接数卡在 1k–5k,不是代码写得差,而是系统资源没放开、Nginx 没配对、服务端事件模型没选准——这三个环节任一没调好,65535 这个理论上限就永远只是理论。
Linux 文件描述符与内核参数必须改
每个 WebSocket 连接会占用至少 1 个文件描述符(fd),而 Linux 默认 ulimit -n 是 1024。不改这个,listen() 队列满、accept() 失败、新连接直接被拒绝,日志里常看到 Too many open files 或静默丢连接。
- 临时生效:
ulimit -n 65535(需在启动服务的同一 shell 中执行) - 永久生效:向
/etc/security/limits.conf追加两行:* soft nofile 1048576和* hard nofile 1048576,并确认 Nginx / Workerman / GoAccess 等进程由该用户启动 - 同步调优内核:
/etc/sysctl.conf加入net.core.somaxconn = 65535、net.ipv4.tcp_tw_reuse = 1、net.ipv4.ip_local_port_range = 1024 65535,再执行sysctl -p
Nginx 代理 WebSocket 必须显式透传 Upgrade 头
90% 的“连不上”问题出在这里:Nginx 默认把 WebSocket 握手当成普通 HTTP 请求处理,过滤掉 Upgrade 和 Connection 头,导致后端收不到升级请求,返回 200 而非 101 —— 客户端报错 Unexpected response code: 200。
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- location 块中必须写全这三行:
proxy_http_version 1.1、proxy_set_header Upgrade $http_upgrade、proxy_set_header Connection "upgrade" -
proxy_read_timeout和proxy_send_timeout建议设为86400(24 小时),不能沿用默认的 60 秒,否则空闲心跳期间连接会被主动切断 - 务必关闭缓冲:
proxy_buffering off;禁用缓存:proxy_cache off;否则消息可能延迟甚至丢失
服务端事件循环模型决定单机吞吐天花板
Workerman 默认用 Select,GoAccess 用 poll,Node.js 默认 libuv,Python websockets 库默认启用压缩——这些选择直接影响每连接内存开销和并发极限。
- Workerman:在
start_gateway.php中启用Libevent扩展(比 Select 高效得多),并把$gateway->count设为 CPU 核心数的 1–2 倍(如 8 核设 8–16) -
websockets(Python):禁用压缩可将单连接内存从 ~64KB 降至 ~14KB,加参数
compression=None - ASP.NET Core:避免默认的 Thread-per-Connection,改用
Sockets + Libuv + Object Pooling,实测连接数可从 5 万跃升至 90 万+ - 心跳间隔要和服务端读超时匹配:例如设
pingInterval = 30,则服务端read timeout至少为 60 秒,留出网络抖动余量
连接数限制不能只靠代码硬限,得结合 IP 限流与连接池
光在业务层用 if (connections > 10000) { ws.close() } 治标不治本——恶意客户端仍能打满 fd 上限,触发系统级拒绝服务。
- 在网关或反向代理层做 IP 级限流:Nginx 可用
limit_conn perip 100(配合limit_conn_zone $binary_remote_addr zone=perip:10m) - 服务端实现轻量连接池(非数据库那种),控制活跃连接复用或排队,比如
WebSocketPool类限制最大持有连接数,超限时直接ws.close()而非堆积等待 - 真正上规模(>10 万连接)时,别死磕单机,用 Redis Pub/Sub 做跨节点广播,用 IP Hash 或一致性哈希保证路由稳定,把连接压力分摊出去
最容易被忽略的是:所有配置改完后,不验证是否真正生效。比如 worker_connections 65535 写了,但忘了配 worker_rlimit_nofile,结果 Nginx 进程自己打不开那么多 socket;又或者心跳设了 30 秒,但客户端实际发 ping 的间隔是 45 秒,服务端早把连接踢掉了——这些细节不逐层对齐,优化就白做了。










