Too many open files at 1000 req/sec

Maxim Dounin mdounin at mdounin.ru
Sun Aug 10 16:25:27 UTC 2025


Hello!

On Sun, Aug 10, 2025 at 07:28:20AM -0700, Zsolt Ero wrote:

>  Hello Maxim and thank you for your detailed answer.
> 
> First, about `multi_accept`: I can confirm that it indeed distributes
> requests super unevenly.
> Luckily I have 2 servers, handling 50-50% of the requests, so I could
> experiment by turning it off on one and restarting the nginx service on
> both.
> 
> multi_accept: on
> 
> for pid in $(pgrep -f "nginx: worker"); do echo "PID $pid: $(lsof -p $pid |
> wc -l) open files"; done
> PID 1761825: 66989 open files
> PID 1761827: 8766 open files
> PID 1761828: 962 open files
> PID 1761830: 184 open files
> PID 1761832: 46 open files
> PID 1761833: 81 open files
> PID 1761834: 47 open files
> PID 1761835: 40 open files
> PID 1761836: 45 open files
> PID 1761837: 44 open files
> PID 1761838: 40 open files
> PID 1761839: 40 open files
> 
> multi_accept: off
> PID 1600658: 11137 open files
> PID 1600659: 10988 open files
> PID 1600660: 10974 open files
> PID 1600661: 11116 open files
> PID 1600662: 10937 open files
> PID 1600663: 10891 open files
> PID 1600664: 10934 open files
> PID 1600665: 10944 open files
> 
> This is from an everyday, low-load situation, not CDN "Purge Cache" or
> similar flood.
> 
> Based on this, multi_accept: on clearly makes no sense, I wonder why it's
> written in so many guides. Back then, I went through blog
> posts/optimisation guides/StackOverflow before I ended up on the config I
> used. multi_accept: on was in many of them.

The "multi_accept on;" can be useful when there are lots of 
connections to handle, and its effect can be easily seen in 
benchmarks (and that's probably why "guides" tend to recommend 
it).  Uniform distribution of requests between worker processes, 
however, isn't something it provides.

On the other hand, in situations where "multi_accept" is 
beneficial, distribution likely will be much better than you've 
observed, since all worker processes will be busy handling 
connections.  Also, uniform distribution can be achieved by other 
means, such as with "listen .. reuseport".

[...]

> 3. What I didn't say was that the files are from a read-only mounted
> disk-image (btrfs loop,ro 0 0). I guess modern Linux kernel level caching
> should be quite optimised for this scenario, shouldn't it? I believe
> open_file_cache in my situation introduces a huge complexity surface with
> possibly no upside? I'll be definitely turning it off altogether.

Yes, exactly.  Most likely it saves you some CPU seconds due to 
smaller number of syscalls made, but provides little to no real 
benefits.

> 4. Now for the limits/connections, I feel it's bit of a deeper water.
> Currently (at normal load) I have this on the multi accept off server:
> 
> ss -Htnp state established '( sport = :80 or sport = :443 )' \
>   | awk 'match($0,/pid=([0-9]+)/,m){c[m[1]]++} END{for (p in c) printf
> "nginx worker pid %s: %d ESTAB\n", p, c[p]}' \
>   | sort -k6,6nr
> nginx worker pid 1600658: 203 ESTAB
> nginx worker pid 1600659: 213 ESTAB
> nginx worker pid 1600660: 211 ESTAB
> nginx worker pid 1600661: 201 ESTAB
> nginx worker pid 1600662: 220 ESTAB
> nginx worker pid 1600663: 214 ESTAB
> nginx worker pid 1600664: 213 ESTAB
> nginx worker pid 1600665: 212 ESTAB
> 
> and this on the multi accept on one:
> 
> nginx worker pid 1761825: 1388 ESTAB
> nginx worker pid 1761827: 114 ESTAB
> nginx worker pid 1761828: 6 ESTAB

So it looks like even the default worker_connections (512) will 
work for you under normal conditions.  But, obviously enough, 
there should be some reserve to handle load spikes.

> Isn't the default http2 128 streams a bit of a too high value?

Yep, it comes from HTTP/2 specification, which says
(https://datatracker.ietf.org/doc/html/rfc9113#section-6.5.2-2.6.1):

: It is recommended that this value be no smaller than 100, so as to 
: not unnecessarily limit parallelism.

Yet I think that it might be a good idea to actually limit 
parallelism to a much smaller value by default.

> What do you think about
> 
> worker_connections 8192;
> 
> http2_max_concurrent_streams 32;
> 
> => 8192 * (32+1) = 270,336 < 300k

Looks good to me.

> Also what do you think about adding http2_idle_timeout 30s;

There is no http2_idle_timeout since nginx 1.19.7, 
keepalive_timeout is used instead for both HTTP/1.x and HTTP/2, 
and the default is 75s.

Also, idle connections in HTTP/2, as well as keepalive 
connections in HTTP/1.x, are subject to LRU-based reuse if there 
aren't enough worker_connections, effectively auto-tuning 
keepalive_timeout.  As such, manual tuning to reduce connection 
usage isn't really needed.

-- 
Maxim Dounin
http://mdounin.ru/


More information about the nginx mailing list