一、Nginx 处理请求的全流程

调优的前提是理解流程。一个 HTTP 请求进来到响应出去,Nginx 经历这些环节:

调优的本质:让每个环节少阻塞、少等待、少浪费。

二、Worker 进程调优

2.1 worker_processes — 开几个进程

# 不要用auto,手动指定更可控
# 规则:CPU几核就开几个,不用多开(多了反而争抢CPU)
worker_processes 4;

怎么看CPU核数:nproc 或 lscpu | grep ‘CPU(s)’

2.2 worker_cpu_affinity — 进程绑核

# 4核绑4个进程,一一对应,避免CPU缓存失效
worker_cpu_affinity 0001 00100100 1000;

原理:如果worker进程在CPU核心间跳来跳去,L1/L2缓存会失效,性能下降。绑核让每个进程固定在一个核心上跑,缓存命中率高。

2.3 worker_rlimit_nofile — 文件描述符上限

# 每个worker最多打开的文件描述符数
# 计算:worker_connections × 2(一进一出)+ 静态文件数
# 生产环境建议直接给大
worker_rlimit_nofile 65535;

同时记得修改系统级限制,否则Nginx配了也没用:

# 临时生效
ulimit -n 65535

# 永久生效,写入 /etc/security/limits.conf
* soft nofile 65535
* hard nofile 65535

2.4 worker_connections — 单个进程的最大并发连接数

events {
    # 单个worker最大并发连接
    # 总并发 = worker_processes × worker_connections
    # 4 × 65535 = 262140 并发连接
    worker_connections 65535;
}

注意:这个值不是越大越好。每个连接都占内存,65535连接大约占 65535 × 4KB ≈ 256MB 内存/worker。根据实际内存算。

三、网络层调优

3.1 accept_mutex — 惊群问题

events {
    # 高并发场景(worker_connections > 1024)建议关闭
    # 关闭后所有worker争抢accept,Linux内核3.9+有REUSEPORT支持,效率更高
    # 低并发场景开启,避免空闲唤醒
    accept_mutex off;
}

什么是惊群:一个新连接来了,所有worker都被唤醒争抢,但只有一个能拿到,其余白跑一趟。accept_mutex on 让worker排队拿连接,避免争抢,但在高并发下排队本身也成了瓶颈。

3.2 多核负载均衡 — SO_REUSEPORT

http {
    # 静态文件传输用零拷贝,跳过用户空间
    # 数据直接从磁盘到内核缓冲区再到网卡,不走用户态
    sendfile on;
}

原理对比:
默认:磁盘 → 内核缓冲区 → 用户缓冲区 → socket缓冲区 → 网卡
sendfile:磁盘 → 内核缓冲区 → 网卡 (少拷贝2次)

3.4 tcp_nopush 和 tcp_nodelay

http {
    sendfile on;

    # 和sendfile配合使用
    # 等数据包攒到最大再一次性发出去,减少网络包数量
    tcp_nopush on;

    # 对于动态内容/小包场景,禁用Nagle算法,有数据立即发
    # 和tcp_nopush不冲突:sendfile时用nopush,非sendfile时用nodelay
    tcp_nodelay on;
}

简单理解:tcp_nopush 是”攒够再发”,适合大文件;tcp_nodelay 是”有就发”,适合API响应。Nginx内部会自动切换。

3.5 keepalive — 长连接复用

http {
    # 客户端长连接超时,默认75s,生产建议65s
    # 太长占连接,太短频繁握手
    keepalive_timeout 65;

    # 长连接最大请求数,超过就断开重连
    # 防止单个连接占用过久
    keepalive_requests 10000;
}

3.6 upstream 长连接(重点,很多人忽略)

upstreambackend {
    # 保持到后端的长连接池,避免每次请求都重新握手
    # 减少Nginx和后端之间的TCP连接开销
    keepalive 32;

    server 10.0.0.1:8080;
    server 10.0.0.2:8080;
}

server {
    location /api/ {
        proxy_pass http://backend;

        # 这三行必须加,否则长连接不生效!
        proxy_http_version 1.1;
        proxy_set_header Connection "";
    }
}

为什么重要:默认情况下Nginx到后端是短连接,每个请求都新建TCP连接。高并发下这是巨大的性能浪费。加上这三行后,Nginx和后端之间会复用长连接,QPS提升非常明显。

四、缓冲与压缩调优

4.1 gzip 压缩

http {
    gzip on;
    gzip_min_length 1k;          # 小于1KB不压缩,压缩反而更大
    gzip_comp_level 4;           # 压缩级别1-9,4是性价比最高的
    gzip_types text/plain application/json application/javascript
               text/css application/xml text/javascript
               application/x-javascript image/svg+xml;
    gzip_vary on;                # 加Vary头,让CDN正确缓存
    gzip_disable "MSIE [1-6]\.";   # IE6不支持gzip
}

压缩级别选择:

级别 压缩率 CPU消耗
1 极低
4 中等 适中
6 较高 较高
9 最高 极高

4.2 proxy_buffer — 代理缓冲

http {
    # 后端响应的缓冲区设置
    proxy_buffering on;           # 开启缓冲,Nginx先收完再转给客户端
    proxy_buffer_size 4k;         # 响应头的缓冲区大小
    proxy_buffers 8 16k;          # 响应体的缓冲区,8个16KB块
    proxy_busy_buffers_size 32k;  # 忙时缓冲区大小

    # 后端响应慢时,先写到临时文件
    proxy_temp_path /tmp/nginx_proxy_temp;
    proxy_max_temp_file_size 1024m;
}

原理:开了buffering,Nginx先把后端响应吃进缓冲区,然后慢慢喂给慢速客户端。后端可以尽快释放去处理下一个请求。如果关掉,后端必须等客户端收完才能脱身。

五、静态文件优化

5.1 开启文件缓存

http {
    # 打开文件描述符缓存,避免重复open/stat系统调用
    # 适合大量静态文件的场景
    open_file_cache max =10000 inactive=30s;
    open_file_cache_valid 60s;      # 60s检查一次文件是否变化
    open_file_cache_min_uses 2;     # 30s内被访问2次以上才缓存
    open_file_cache_errors on;      # 缓存文件不存在的错误响应
}

实测效果:静态文件密集场景,QPS提升 2-3倍。

5.2 静态资源缓存头

server {
    location /static/ {
        alias  /data/www/static/;

        # 浏览器缓存30天,期间不会重复请求
        expires 30d;
        add_header Cache-Control "public, immutable";

        # 开启etag,文件变化时浏览器自动刷新缓存
        etag on;
    }

    # HTML文件不缓存,保证用户拿到最新版本
    location / {
        root /data/www;
        expires -1;
        add_header Cache-Control "no-cache";
    }
}

六、安全相关调优

6.1 隐藏版本号

http {
    # 隐藏Nginx版本号,防止针对性攻击
    server_tokens off;
}

6.2 限制请求方法

server {
    # 只允许GET、POST和HEAD,其他全拒
    if ($request_method !~ ^(GET|POST|HEAD)$ ) {
        return 405;
    }
}

6.3 限流限并发

http {
    # 基于IP的请求限流:每秒10个请求,突发允许20个
    limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;

    # 基于IP的并发连接限制:每个IP最多20个并发
    limit_conn_zone $binary_remote_addr zone=conn_limit:10m;

    server {
        location  /api/ {
            # burst=20 nodelay:突发20个立即处理,不排队
            limit_req zone=api_limit burst=20 nodelay;
            limit_conn conn_limit 20;

            proxy_pass http://backend;
        }
    }
}

$binary_remote_addr vs $remote_addr:二进制格式一个IP只占16字节,文本格式占7-15字节。10MB的共享内存用二进制可以存约60万条记录,文本格式只有一半。

6.4 超时设置防慢速攻击

http {
    # 客户端请求头超时
    client_header_timeout 15s;
    # 客户端请求体超时
    client_body_timeout 15s;
    # 客户端两次写操作之间的超时
    send_timeout 15s;

    # 限制请求体大小,防止大文件上传打满内存
    client_max_body_size 20m;
    # 限制请求头缓冲区大小
    client_header_buffer_size 4k;
}

七、日志优化

7.1 关掉不必要的访问日志

http {
    # 访问日志占大量IO,尤其是SSD场景
    # 健康检查、静态资源等可以不记录

    # 方法1:直接全局关掉(不推荐,出问题没日志排查)
    # access_log off;

    # 方法2:条件记录(推荐,生产环境访问日志过多时,可选择配置)
    map $status $loggable {
        ~^[23] 0;   # 2xx和3xx不记录
        default 1;   # 4xx和5xx记录
    }

    access_log  /var/log/nginx/access.log combined if=$loggable;
}

server {
    # 静态文件不记日志
    location /static/ {
        access_log off;
        alias /data/www/static/;
    }
}

7.2 日志缓冲

http {
    # 缓冲16KB再写磁盘,减少IO次数
    # open_log_file_cache缓存日志文件描述符
    access_log /var/log/nginx/access.log combined buffer=16k flush=5s;
    open_log_file_cache max=1000 inactive=20s;
}

八、系统内核参数调优

Nginx配得再好,系统参数不配合也白搭。以下参数写入 /etc/sysctl.conf:

# 允许TIME_WAIT socket复用,高并发必开
net.ipv4.tcp_tw_reuse =1

# TIME_WAIT最大数量,默认太小
net.ipv4.tcp_max_tw_buckets =65535

# TCP连接队列长度,超过这个值的连接会被丢弃
# 等于 min(somaxconn, 应用backlog) 的较小值
net.core.somaxconn =65535

# SYN队列长度,防SYN Flood
net.ipv4.tcp_max_syn_backlog =65535

# SYN重试次数,默认5次太慢
net.ipv4.tcp_synack_retries =2

# FIN_WAIT2状态超时时间
net.ipv4.tcp_fin_timeout =15

# keepalive探测间隔
net.ipv4.tcp_keepalive_time =600
net.ipv4.tcp_keepalive_intvl =30
net.ipv4.tcp_keepalive_probes =3

# 本地端口范围(临时端口)
net.ipv4.ip_local_port_range =102465535

# TCP读写缓冲区最小/默认/最大值
net.ipv4.tcp_rmem =40968738016777216
net.ipv4.tcp_wmem =40966553616777216

# 网卡收发队列长度
net.core.netdev_max_backlog =65535

# 文件描述符上限
fs.file-max =2000000

生效命令:

sysctl -p
作者:柳杨  创建时间:2026-05-28 08:59
最后编辑:柳杨  更新时间:2026-06-11 18:29