需同步调高系统四层文件描述符上限:内核层(fs.file-max)、用户层(limits.conf)、systemd层(limitnofile)、nginx进程层(worker_rlimit_nofile),并匹配调优worker_connections及内核参数,配合超时、限流与日志优化防句柄耗尽。

高并发 WebSocket 场景下,Nginx 报 “Too many open files” 或 “socket() failed (24: Too many open files)” 并非配置遗漏,而是系统级资源限制未对齐。每个连接至少占用 1 个文件描述符(fd),千级连接就可能突破默认 1024 限制,必须从系统、服务管理器、Nginx 进程三层同步扩容。
确认真实瓶颈在哪一层
别直接改配置,先查清楚当前限制值:
- 查 Nginx 主进程用户:ps -eo pid,comm,user | grep nginx | grep master(常见为 nginx 或 www-data)
- 查该用户软硬限制:sudo -u nginx bash -c "ulimit -Sn; ulimit -Hn"
- 查 systemd 是否覆盖:systemctl show nginx | grep LimitNOFILE
- 查 worker 进程实际生效值:cat /proc/$(pgrep nginx | head -2 | tail -1)/limits | grep "Max open files"
同步调高四层文件描述符上限
Linux 的 fd 限制分四层:内核总上限、用户级限制、systemd 服务限制、Nginx 进程级限制。任意一层卡住,Nginx 就只能取最小值。
- 内核层:编辑 /etc/sysctl.conf,添加 fs.file-max = 2097152,执行 sysctl -p
-
用户层:在 /etc/security/limits.conf 中添加(用户名需匹配):
nginx soft nofile 1048576
nginx hard nofile 1048576 -
systemd 层(若用 systemd 启动):新建 /etc/systemd/system/nginx.service.d/override.conf,写入:
[Service]
LimitNOFILE=1048576
然后执行 systemctl daemon-reload && systemctl restart nginx -
Nginx 进程层:在 nginx.conf 的 main 块(events 块之前、http 块之外)添加:
worker_rlimit_nofile 1048576;
注意:数值不能超过用户 hard nofile 值,建议设为 hard 值的 90% 左右
关联调优 worker_connections 和内核参数
仅调大 fd 上限不够,还需让 Nginx 实际用得上这些资源:
- worker_connections 应设为 worker_rlimit_nofile 的 70%~90%。例如设了 1048576,则可配 events { worker_connections 80000; }
- 检查并优化关键内核参数:
net.core.somaxconn = 65535
net.ipv4.ip_local_port_range = "1024 65535"
配置后执行 sysctl -p
避免无效连接持续占坑
句柄耗尽常源于大量“半死不活”的连接——建连成功但无心跳、无数据、不释放。需主动干预:
- 设置合理 proxy_read_timeout:不是越长越好。若客户端心跳间隔为 30 秒,设为 60~300 秒更稳妥;设为 86400(24 小时)虽能防误杀,但异常连接会长期滞留
- 用 limit_req 对高频建连行为限速,例如每 IP 每分钟最多 5 次握手请求,过滤爬虫或崩溃重连风暴
- 关闭 access_log 和降低 error_log 级别(如设为 warn),减少日志 I/O 对 fd 和内存的额外开销











