Nginx Performance Tuning and Limits: Worker Processes, Connections, CPU Priority, and I/O Optimization
This article explains how to tune Nginx for high‑concurrency environments by adjusting OS limits, worker processes, worker connections, CPU priority, keep‑alive settings, TCP options, logging, caching, and I/O strategies to achieve optimal performance without relying on magical configurations.
Nginx is already well‑optimized out of the box, but when handling hundreds of requests per second you may need to adjust both operating‑system limits and Nginx directives to ensure high‑concurrency performance.
Operating‑system limits : Check the current limits with ulimit -a . The default "open files" limit is often 1024, which can cause "Too many open files" errors. Increase this limit either via the shell ( ulimit -n 65535 ) or by setting worker_rlimit_nofile in the Nginx configuration.
Worker Processes : Each worker is a single‑process, not multithreaded, and should not exceed the number of CPU cores. Typically one worker per core (1‑4 workers) is optimal; more workers can cause CPU contention.
Worker Connections : This directive caps the number of simultaneous connections a worker can handle. The default is 1024, which may allow roughly 512 concurrent users. Increase it (e.g., to 2048) when traffic grows, keeping in mind the keep‑alive timeout.
CPU Priority : Adjusting CPU affinity can bind Nginx processes to specific cores, but it should be done with caution because modern schedulers already balance load efficiently.
Keep‑Alive : Enabling keep‑alive reduces the overhead of establishing new TCP connections. A timeout of 10‑20 seconds is generally sufficient; Nginx can handle tens of thousands of idle connections with modest memory usage.
tcp_nodelay and tcp_nopush : These low‑level TCP options control packet buffering and transmission. They are rarely needed to be changed; the defaults work well for most scenarios.
Hardware and I/O bottlenecks : CPU and memory are usually not limiting factors for Nginx; disk I/O often is. Reduce disk reads/writes by disabling unnecessary access logs, using in‑memory logging, enabling open file caching, and tuning buffer sizes.
Access and Error Logs : Access logs can be disabled or written to memory to cut I/O. Error logs should be set to an appropriate level (e.g., warn ) to avoid excessive writes.
Open File Cache : Caching file descriptors with open_file_cache reduces the overhead of opening and closing files repeatedly.
Buffers : Properly size client_body_buffer_size , fastcgi_buffers , and proxy_buffers to avoid spilling data to disk under heavy load.
Eliminating Disk I/O : When possible, keep data in memory to avoid disk latency. Sufficient RAM can mitigate I/O bottlenecks for read‑heavy workloads.
Network I/O : Even with ample memory, network bandwidth can become a limit. Use gzip compression ( gzip_comp_level 4‑5 ) to reduce payload size, and consider additional front‑end optimizations (minifying JS/CSS) to lower transferred data.
Architect
Professional architect sharing high‑quality architecture insights. Topics include high‑availability, high‑performance, high‑stability architectures, big data, machine learning, Java, system and distributed architecture, AI, and practical large‑scale architecture case studies. Open to ideas‑driven architects who enjoy sharing and learning.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.