How to Tune Nginx for Million‑Level Concurrency: Key Optimizations

This article explains how to configure Nginx and the underlying Linux system to handle millions of concurrent connections by optimizing the I/O model with epoll, scaling worker processes, enabling zero‑copy sendfile, using gzip compression, and tuning kernel parameters and CPU affinity.

Architect
Architect
Architect
How to Tune Nginx for Million‑Level Concurrency: Key Optimizations

When building high‑concurrency systems, Nginx is a core component, but achieving million‑level concurrent connections requires more than a simple installation; it involves OS, network stack, and fine‑tuned Nginx settings.

1. Connection handling model: choose epoll to unleash Linux kernel potential

Nginx’s performance stems from its advanced I/O multiplexing model. In Linux, epoll is the foundation for high‑concurrency services, offering a qualitative leap over traditional select and poll.

select / poll bottleneck: Both poll the entire descriptor set on each call, causing CPU overhead that grows with connection count.

epoll advantage: It uses an event‑driven mechanism. The application creates an epoll instance with epoll_create, registers events via epoll_ctl, and retrieves ready descriptors with epoll_wait in O(1) time, avoiding full scans.

events {
    # Recommend explicitly using epoll on Linux for best performance
    use epoll;
    # Max connections per worker
    worker_connections 65535;
}

2. Worker processes and connections: fully utilize multi‑core CPUs

Nginx uses a master‑worker architecture. The master manages workers; workers handle network requests. Key directives are worker_processes and worker_connections. worker_processes: Set to the number of CPU cores (or auto) to avoid CPU contention. worker_connections: Defines the maximum concurrent connections per worker. The theoretical maximum is worker_processes × worker_connections, but the value is limited by the OS file‑descriptor limit ( ulimit -n).

Maximum concurrent connections = worker_processes × worker_connections

Ensure the system allows enough file descriptors before deployment.

# Increase SYN queue length
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535

# Reuse TIME_WAIT sockets
net.ipv4.tcp_tw_reuse = 1

# Raise system‑wide file descriptor limits
fs.file-max = 655350
fs.nr_open = 655350

3. Data transfer efficiency: sendfile zero‑copy and gzip compression

When serving static files, the traditional read + write path copies data between kernel and user space, wasting CPU and memory bandwidth.

Enabling sendfile lets the kernel transfer data directly from the page cache to the network card, eliminating user‑space copies.

http {
    # Enable zero‑copy
    sendfile on;
    tcp_nopush on;
}

For text resources (HTML, CSS, JS), enabling gzip reduces network traffic by trading CPU cycles for bandwidth.

http {
    gzip on;
    gzip_min_length 1k;    # Do not compress very small files
    gzip_comp_level 6;      # Balanced compression level
    gzip_types text/plain application/javascript text/css;
}

4. System‑level collaborative optimization: unleash hardware and kernel potential

High‑concurrency often hits OS limits. Adjust kernel parameters in /etc/sysctl.conf to enlarge connection queues and file‑descriptor limits.

# Increase SYN queue
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535

# Reuse TIME_WAIT sockets
net.ipv4.tcp_tw_reuse = 1

# Raise file descriptor limits
fs.file-max = 655350
fs.nr_open = 655350

Binding workers to specific CPU cores (CPU affinity) reduces context switches and improves cache hit rates.

# Assume a 4‑core CPU
worker_processes 4;
worker_cpu_affinity 0001 0010 0100 1000;

When Nginx acts as a reverse proxy, keepalive connections to upstream servers avoid repeated TCP handshakes.

upstream backend_servers {
    server 192.168.1.101:8080;
    server 192.168.1.102:8080;
    # Keep 100 persistent connections per worker
    keepalive 100;
}

server {
    location /api/ {
        proxy_pass http://backend_servers;
        proxy_http_version 1.1;   # Enable HTTP/1.1 for keep‑alive
        proxy_set_header Connection ""; # Clear Connection header
    }
}

Summary

Nginx’s million‑concurrency optimization is a systematic effort that starts with fine‑tuned Nginx settings—epoll I/O, worker processes, sendfile zero‑copy, gzip compression—and extends to OS‑level kernel tuning, CPU affinity, and upstream keepalive. Understanding both the “what” and the “why” enables architects to diagnose and adjust performance for diverse workloads.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

backend-developmentLinuxhigh concurrencyNginx
Architect
Written by

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.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.