Nginx 高并发配置实战:worker 调优、keepalive、动静分离与限流防护
同样的服务,有人用 Nginx 反代压测 2 万并发就各种超时,有人能扛 10 万+。差别不在 Nginx 本身,而在配置文件有没有按高并发场景调优。本文从 Nginx 的进程模型讲起,给出一套面向高并发的完整配置:worker 进程与连接数、epoll 事件模型、keepalive 连接复用、gzip 与静态缓存、限流防护,最后配一张可直接改改用的参考配置。
先理解模型:为什么 Nginx 能扛高并发
Nginx 采用 master + worker 多进程 + 事件驱动(epoll)架构:master 负责加载配置、管理 worker;worker 进程各自独立监听端口,用 epoll 同时管理成千上万条连接,一个 worker 单线程就能支撑数万并发连接——因为它是异步非阻塞的,连接空闲时不占线程。这跟 Apache 的"一连接一线程"模型有本质区别,也是 Nginx 高并发的根基。
理解了这个模型,所有调优参数就都顺理成章了:调优的目标是让每个 worker 能处理更多连接、让连接更快被处理完、让每个连接占用更少的资源。
worker 进程与事件模型调优
worker 进程数一般等于 CPU 核数,避免进程切换开销;worker 连接数决定了单进程能承载的连接上限:
worker_processes auto; # = CPU 核数,或手动写 8 之类
worker_rlimit_nofile 65535; # 单进程可打开文件数上限,必须调大
events {
use epoll; # Linux 高并发下的事件模型
worker_connections 65535; # 单 worker 最大连接数
multi_accept on; # 一次 accept 多个新连接,减少唤醒
}
最大并发连接数的估算:总连接数约 = worker_processes × worker_connections(再考虑反向代理场景每个客户端连接会占两倍:一条对客户端、一条对上游)。所以 8 核 × 65535 ≈ 52 万理论连接上限,实际受系统文件句柄、内存和带宽限制。
配合的内核参数(需要 root,写入 /etc/sysctl.conf):
# 端口监听队列与文件句柄
net.core.somaxconn = 65535
fs.file-max = 1000000
net.ipv4.tcp_max_syn_backlog = 65535
HTTP 层:连接复用与协议优化
高并发下最容易被忽视的是连接开销。HTTP/1.1 的 keepalive 让客户端复用 TCP 连接,避免每次请求都三次握手;反向代理到上游 Java 服务的连接也要复用,否则高并发时频繁新建 TCP 连接会拖垮上游:
http {
keepalive_timeout 65; # 客户端长连接超时
keepalive_requests 1000; # 单条长连接最多处理请求数
# gzip 压缩,显著降低传输体积(HTML/CSS/JS 可省 60%+)
gzip on;
gzip_min_length 1k;
gzip_comp_level 5; # 1-9,5 是性价比点
gzip_types text/plain text/css application/javascript application/json image/svg+xml;
gzip_vary on;
}
静态资源用浏览器缓存 + open_file_cache 减少磁盘 IO:
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff2?)$ {
expires 7d; # 浏览器缓存 7 天
access_log off;
open_file_cache max=10000 inactive=20s; # 缓存文件句柄
open_file_cache_valid 60s;
open_file_cache_min_uses 2;
}
反向代理 + 负载均衡:高并发架构的核心
Nginx 最常用的高并发姿势是扛在最前面,把请求分发到多个 Java 后端。upstream 定义后端集群,proxy_pass 转发:
upstream backend {
# 默认轮询;ip_hash 可让同一客户端固定后端(有状态会话)
least_conn; # 转发给当前连接最少的后端,更均衡
server 10.0.0.11:8080 weight=5 max_fails=2 fail_timeout=30s;
server 10.0.0.12:8080 weight=3;
server 10.0.0.13:8080 backup; # 备用机,前两台挂了才启用
keepalive 64; # 每个 worker 对上游保持的空闲长连接数(关键!)
}
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://backend;
proxy_http_version 1.1; # 上游连接复用必须用 1.1
proxy_set_header Connection ""; # 清掉 Connection 头才能复用
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 5s; # 连不上后端快速失败,别都堆在超时上
proxy_read_timeout 30s;
proxy_send_timeout 30s;
# 响应缓冲:吞吐优先可加大,实时性要求高可关小
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
}
}
这里最容易踩的坑是忘了 proxy_http_version 1.1 和空 Connection 头,导致 upstream keepalive 不生效——高并发下后端会看到大量新建连接,连接数瞬间打满,表现为偶发 502/超时。
限流与防护:高并发下的"安全阀"
只调性能不够,还得防突刺。Nginx 内置 ngx_http_limit_req_module(漏桶限流)和 limit_conn(连接数限制),给接口装上安全阀:
http {
# 定义限流区:按 IP,每秒 10 请求,突发 20
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
# 定义连接数限制区
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
server {
location /api/ {
limit_req zone=api_limit burst=20 nodelay; # 突发 20 后拒绝
limit_conn conn_limit 50; # 单 IP 最多 50 并发
proxy_pass http://backend;
}
}
}
限流返回 503 而不是 502,语义更准确;配合 error_page 把限流响应做成友好提示页。
动静分离:把 Nginx 的性能用在刀刃上
静态资源(图片/JS/CSS)由 Nginx 直接返回,动态请求(/api/、/user/ 等)才转发 Java。这是最经典的高并发架构:Nginx 吃下 80% 的静态流量,后端只扛真正的业务请求。如果静态资源量很大,再叠一层 CDN,把压力挡在更前面。
server {
listen 80;
server_name www.example.com;
root /data/www; # 静态文件根目录
location / { } # 命中静态文件直接返回
location /api/ { # 动态请求转后端
proxy_pass http://backend;
proxy_set_header Host $host;
}
}
高并发压测自检清单
配置完别急着上线,先自检这五项:1. worker_processes 是否 = 核数、worker_connections 是否调大;2. 系统 somaxconn / file-max 是否同步调大(Nginx 配了系统不配等于白配);3. 反代场景是否开了 upstream keepalive + HTTP/1.1;4. 静态资源是否有 expires 缓存;5. 是否有 limit_req/limit_conn 兜底。用 wrk 或 ab 压测看 QPS 与错误率,逐步逼近瓶颈。
一句话总结:Nginx 高并发不是某一个参数调出来的,而是"进程模型 + 连接复用 + 缓存分流 + 限流兜底 + 系统内核"整套配合的结果。