Please use this template for troubleshooting questions.
My issue:
We are seeing an extremely uneven distribution of long-lived WebSocket connections between NGINX workers.
We currently have about 9000–10000 devices maintaining long-lived WebSocket connections through NGINX.
With 9253 connected devices, we observed:
worker 911 : 461 FDs
worker 912 : 39 FDs
worker 913 : 18226 FDs
worker 914 : 47 FDs
So almost all connections are handled by a single worker.
Each device creates approximately two NGINX-side TCP sockets:
device → NGINX
NGINX → WebSocket application server
The practical consequence is that one worker approaches worker_connections while the other workers are nearly idle.
How I encountered the problem:
We initially had: worker_connections 20000;
One worker reached that limit and NGINX started logging: worker_connections are not enough while connecting to upstream
This caused production issues for other proxied applications as NGINX could no longer open new upstream connections.
The server was previously running Debian 11 / NGINX 1.18.0.
We upgraded the server to Debian 12 / NGINX 1.22.1 and performed a full reboot, forcing all WebSocket clients to reconnect from scratch.
The same extreme worker imbalance is still present after the upgrade.
Solutions I’ve tried:
Increased worker_connections from 20000 to 22000 as a temporary safety margin.
Verified worker_rlimit_nofile 100000.
Upgraded from Debian 11 / NGINX 1.18.0 to Debian 12 / NGINX 1.22.1.
Performed a full server restart.
Monitored file descriptors per worker during the complete reconnection of the devices. Verified that RAM and CPU are not currently exhausted.
We have not yet changed multi_accept or enabled reuseport.
We are considering testing multi_accept off next.
Version of NGINX or NGINX adjacent software (e.g. NGINX Gateway Fabric):
Debian GNU/Linux 12 (bookworm)
nginx version: nginx/1.22.1
built with OpenSSL 3.0.20
Linux epoll
4 worker processes
Relevant limits:
Max open files: 100000 per worker
worker_connections: 22000
Deployment environment:
The architecture is:
~10000 devices
|
| WSS / TCP 443
v
NGINX frontend
Debian 12
4 vCPU / 8 GB RAM
|
| proxied WebSocket connection
v
Application server
WebSocket service on TCP port 9014
NGINX terminates TLS and proxies the WebSocket connection to one application server.
The WebSocket connections are long-lived, typically remaining established for hours or days.
There is no load balancer in front of NGINX.
Minimal NGINX config to reproduce your issue :
worker_processes auto;
worker_rlimit_nofile 100000;
events {
use epoll;
worker_connections 22000;
multi_accept on;
}
http {
upstream websocket_backend {
server 10.x.x.x:9014;
}
server {
listen 443 ssl http2;
location / {
proxy_pass http://websocket_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection “upgrade”;
proxy_read_timeout 620s;
proxy_send_timeout 620s;
}
}
}
NGINX access/error log:
When the busy worker reached the configured limit, we observed:
worker_connections are not enough while connecting to upstream
After increasing the limit to 22000, the service is currently running correctly, but the worker distribution is still extremely uneven.
For example:
911 : 461 FDs
912 : 39 FDs
913 : 18226 FDs
914 : 47 FDs
Our main questions are:
Can multi_accept on cause such an extreme imbalance with epoll?
Is testing multi_accept off the recommended next step?
Would reuseport help distribute the initial WebSocket connections more evenly?
Are there additional NGINX/Linux settings we should inspect to understand why almost all connections are accepted by one worker?
Thanks for any advice.