Nginx 性能优化实战指南:从基础配置到高并发压测

Nginx 是全球使用最广泛的 Web 服务器之一,以高性能、低资源占用著称。但默认配置往往保守,没有发挥出 Nginx 的全部潜力。本文系统梳理 2025 年 Nginx 性能优化的核心配置项,从基础参数调优、Gzip 压缩、缓存策略、安全防护到压测验证,配合完整配置示例,帮你将网站性能提升数倍。

Nginx 性能优化实战指南:从基础配置到高并发压测

一、基础配置优化:压榨硬件性能

1.1 worker 进程配置

Nginx 启动后由一个 Master 进程管理一群 Worker 进程。Worker 进程才是真正处理请求的地方,Master 只负责管理。

# /etc/nginx/nginx.conf

# 全局块
user  nginx;
worker_processes  auto;        # ✅ 自动匹配 CPU 核心数(推荐)
worker_cpu_affinity auto;       # ✅ 将 worker 绑定到对应 CPU,减少上下文切换
worker_priority  -5;            # 提高调度优先级(负数越高优先)
worker_rlimit_nofile 65535;     # 每个 worker 能打开的文件描述符数量

# 错误日志
error_log  /var/log/nginx/error.log warn;

# PID 文件
pid        /var/run/nginx.pid;

events {
    worker_connections  10240;   # 每个 worker 最大并发连接数
    use                  epoll;  # ✅ Linux 高效 I/O 事件模型(生产环境必须)
    multi_accept         on;     # ✅ 一次接受多个新连接
}

关键参数解读:

参数 默认值 推荐值 说明
worker_processes 1 auto 自动等于 CPU 核心数
worker_connections 512 10240+ 单进程最大并发数
worker_rlimit_nofile 65535 文件描述符上限,需配合系统 ulimit -n
multi_accept off on 一次接收多个连接,减少 accept() 调用
use epoll epoll Linux 下最高效的事件模型

系统层文件描述符限制:

# 查看当前限制
ulimit -n

# 临时生效(重启失效)
ulimit -n 100000

# 永久生效:编辑 /etc/security/limits.conf
nginx  soft  nofile  100000
nginx  hard  nofile  100000

# 编辑 /etc/sysctl.conf
echo "fs.file-max = 2097152" >> /etc/sysctl.conf
sysctl -p

1.2 HTTP 连接与传输优化

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    # ── 传输效率优化 ──────────────────────────────

    sendfile         on;      # ✅ 启用零拷贝:文件从磁盘直发网络,不走用户态
    tcp_nopush       on;      # ✅ sendfile 开启时:等凑满一个数据包再发,减少小包数量
    tcp_nodelay      on;      # ✅ 禁用 Nagle 算法,小数据包立即发送(适合实时响应)
    aio             on;      # ✅ 异步 I/O,配合 directio 使用(大文件场景)
    directio        512;      # 超过 512KB 的文件用 directio 跳过系统缓存(Linux)
    open_file_cache max=10000 inactive=60s;  # 缓存文件元数据,减少 stat() 系统调用
    open_file_cache_valid    30s;            # 元数据缓存有效期
    open_file_cache_min_use  5;             # 访问 5 次后才缓存

    # ── 连接超时优化 ──────────────────────────────

    keepalive_timeout  65;      # 客户端保持连接时长(65秒)
    keepalive_requests 10000;   # 单连接最大请求数,防止长连接滥用
    client_header_timeout  10s; # 读取请求头超时
    client_body_timeout   10s; # 读取请求体超时
    send_timeout         10s;  # 发送给客户端超时
    reset_timedout_connection on;  # 连接关闭时立即释放内存

    # ── 请求体与请求头限制 ──────────────────────────

    client_max_body_size      50m;  # 最大请求体(上传文件)
    client_header_buffer_size  4k;   # 请求头缓冲区
    large_client_header_buffers 4 32k;  # 大请求头(JWT/长 Cookie 场景)
}

零拷贝原理说明:

传统模式(sendfile off):
  磁盘 → 内核缓冲区 → 用户缓冲区 → Socket缓冲区 → 网卡
  (4 次数据拷贝 + 2 次上下文切换)

零拷贝模式(sendfile on):
  磁盘 → 内核缓冲区 → Socket缓冲区 → 网卡
  (2 次数据拷贝 + 0 次上下文切换)

二、Gzip 压缩:减少 60%-80% 传输量

2.1 Gzip 基础配置

http {
    gzip                on;      # ✅ 启用 Gzip 压缩
    gzip_vary           on;      # ✅ 根据 Accept-Encoding 缓存不同版本
    gzip_proxied       any;      # 代理请求也压缩(即使后端已压缩)
    gzip_disable       "msie6";  # IE6 不支持,禁用

    # 压缩级别(1-9,默认 4)
    # 级别越高压缩率越高,但 CPU 开销越大
    # CDN/中转节点:4-5;自有服务器:5-6;静态资源密集型:6
    gzip_comp_level     5;

    # 最小压缩阈值:小于此大小的文件不压缩(避免浪费 CPU)
    gzip_min_length    1024;

    # ✅ 压缩的文件 MIME 类型
    gzip_types
        text/plain
        text/css
        text/javascript
        application/javascript
        application/json
        application/xml
        application/xml+rss
        application/x-javascript
        application/x-font-ttf
        application/x-web-app-manifest+json
        font/opentype
        font/ttf
        font/eot
        font/otf
        image/svg+xml
        image/x-icon;
}

2.2 Gzip 压缩效果实测

# 未压缩时的响应
curl -I -H "Accept-Encoding: gzip" https://example.com/api/data.json
# Content-Length: 524288   (512KB)

# 启用 Gzip 后(压缩率约 5)
curl -I -H "Accept-Encoding: gzip" https://example.com/api/data.json
# Content-Length: 81920     (80KB)
# 节省约 84% 带宽

2.3 Brotli 压缩(更优选择)

Brotli 是 Google 推出的新一代压缩算法,同等压缩级别下比 Gzip 小 15%-25%:

http {
    # 需要安装 nginx-module-brotli
    load_module modules/ngx_http_brotli_filter_module.so;
    load_module modules/ngx_http_brotli_static_module.so;

    brotli             on;
    brotli_comp_level  6;      # Brotli 压缩级别(1-11)
    brotli_types
        text/plain
        text/css
        application/javascript
        application/json
        application/xml
        image/svg+xml
        font/ttf
        font/otf
        font/eot;
}

三、缓存策略:让静态资源"永不过期"

3.1 浏览器缓存配置

server {
    listen 80;
    server_name example.com;

    root /var/www/html;

    # ── 静态资源缓存(永不过期 + 版本化)──────────────
    location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2|ttf|eot)$ {
        expires         1y;                    # 缓存 1 年
        add_header      Cache-Control "public, immutable";  # immutable:URL 不变则永不变
        add_header      X-Cache-Status $upstream_cache_status;  # HIT/MISS 调试用
        access_log      off;                    # 静态资源关闭日志,省 I/O
    }

    # ── HTML 文件(始终经过后端,确保最新)────────────
    location ~* \.html$ {
        expires         -1;                     # 不缓存,每次请求最新
        add_header      Cache-Control "no-cache, no-store, must-revalidate";
    }
}

3.2 代理缓存(反向代理缓存)

http {
    # ── 代理缓存配置 ──────────────────────────────
    proxy_cache_path  /var/cache/nginx levels=1:2
                     keys_zone=api_cache:100m
                     max_size=10g
                     inactive=60m
                     use_temp_path=off;

    # ── API 缓存策略 ─────────────────────────────
    upstream backend {
        server 127.0.0.1:8080;
        keepalive 32;  # 与后端保持长连接,减少建连开销
    }

    server {
        listen 80;
        server_name api.example.com;

        # ✅ 缓存 GET/HEAD 请求(POST/PUT 等写操作不缓存)
        proxy_cache_lock        on;         # 防止缓存击穿
        proxy_cache_lock_timeout 5s;
        proxy_cache_use_stale  error timeout updating http_500 http_502 http_503;
        proxy_cache_background_update on;     # 后台更新缓存,用户无感知
        proxy_cache_valid       200 60s;     # 200 响应缓存 60 秒
        proxy_cache_valid       404 1m;      # 404 缓存 1 分钟
        proxy_cache_key         "$scheme$request_method$host$request_uri$http_x_custom";  # 含自定义 header 区分用户
        add_header              X-Cache-Status $upstream_cache_status;

        location /api/ {
            proxy_pass         http://backend;
            proxy_cache        api_cache;
            # 缓存清理:缓存失效时立即回源,不等 inactive 时间
            proxy_cache_purge  PURGE from 127.0.0.1;
        }
    }
}

3.3 FastCGI 缓存(PHP 应用)

http {
    # FastCGI 缓存配置
    fastcgi_cache_path /var/cache/nginx/fcgi levels=1:2
                       keys_zone=fcgi_cache:100m
                       max_size=5g
                       inactive=2h;

    server {
        listen 80;
        server_name www.example.com;

        # 绕过缓存的条件
        set $skip_cache 0;
        if ($request_uri ~* "/admin|/login|/cart") {
            set $skip_cache 1;  # 管理后台/登录/购物车不缓存
        }
        if ($http_cookie ~* "wordpress_logged_in") {
            set $skip_cache 1;  # 登录用户不缓存
        }

        location ~ \.php$ {
            fastcgi_pass    127.0.0.1:9000;
            fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include         fastcgi_params;

            # 缓存控制
            fastcgi_cache              fcgi_cache;
            fastcgi_cache_valid       200 10m;
            fastcgi_cache_valid       404 1m;
            fastcgi_cache_bypass     $skip_cache;
            fastcgi_no_cache         $skip_cache;
            fastcgi_cache_lock        on;
            fastcgi_cache_lock_timeout 5s;
            add_header               X-FastCGI-Cache $upstream_cache_status;
        }
    }
}

四、负载均衡与高可用

4.1 常用负载均衡策略

upstream backend_servers {
    # ── 轮询(默认):每台机器轮流处理 ───────────
    # server 10.0.0.11:8080;
    # server 10.0.0.12:8080;
    # server 10.0.0.13:8080 down;  # down 表示永久剔除

    # ── 加权轮询:权重越高,分到的请求越多 ─────────
    server 10.0.0.11:8080 weight=5;
    server 10.0.0.12:8080 weight=3;
    server 10.0.0.13:8080 weight=2 backup;  # backup:仅所有非 backup 节点 down 时启用

    # ── IP 哈希:同一 IP 始终路由到同一后端(适合有状态的场景)
    # ip_hash;

    # ── 最少连接:优先分配给连接数最少的节点 ───────
    least_conn;

    # 长连接复用:减少与后端的建连次数
    keepalive 32;
}

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass         http://backend_servers;
        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_set_header   X-Forwarded-Proto $scheme;

        # 健康检查
        proxy_connect_timeout  5s;
        proxy_read_timeout    30s;
        proxy_next_upstream  error timeout http_502 http_503;  # 失败自动切到下一台
    }
}

4.2 健康检查配置

upstream backend {
    server 10.0.0.11:8080 max_fails=3 fail_timeout=30s;  # 30秒内失败3次则摘除
    server 10.0.0.12:8080 max_fails=3 fail_timeout=30s;
}

五、安全防护配置

5.1 隐藏版本号与敏感信息

server {
    server_tokens off;      # ✅ 关闭 Server 头显示 Nginx 版本号
    add_header  X-Frame-Options       "SAMEORIGIN"      always;
    add_header  X-Content-Type-Options "nosniff"        always;
    add_header  X-XSS-Protection      "1; mode=block"   always;
    add_header  Referrer-Policy       "no-referrer-when-downgrade" always;
    add_header  Permissions-Policy    "geolocation=(), microphone=(), camera=()" always;

    # 自定义 Server 头(迷惑扫描器)
    add_header  Server "Apache/2.4.41" always;
}

5.2 防盗链配置

server {
    server_name example.com;

    # 允许访问的域名白名单
    valid_referers none blocked ~\.google\. ~\.baidu\. example.com *.example.com;

    if ($invalid_referer) {
        return   403;
        # 或者重定向到一张警告图片
        # rewrite ^/.*$ /static/hotlink.jpg break;
    }

    location /uploads/ {
        valid_referers ~\.google\. ~\.baidu\. example.com;
        if ($invalid_referer) {
            return 403;
        }
    }
}

5.3 限流防护

http {
    # ── 连接数限制 ───────────────────────────────
    # 基于 IP 的并发连接数限制
    limit_conn_zone $binary_remote_addr zone=conn_limit:10m;

    # ── 请求速率限制 ───────────────────────────────
    # 每个 IP 每秒最多 10 个请求(令牌桶算法)
    limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s;

    server {
        listen 80;
        server_name example.com;

        # 连接数限制:每个 IP 同时最多 5 个连接
        limit_conn conn_limit 5;

        # 请求速率限制:突发最多 20 个请求,超出的返回 503
        limit_req zone=req_limit burst=20 nodelay;

        # 返回 429 代替默认的 503(更友好的限流提示)
        limit_req_status  429;
        limit_conn_status 429;

        # 限制单个 IP 同时下载速度(bytes/s)
        limit_rate_after 1m;   # 前 1MB 不限速
        limit_rate 200k;       # 之后限速 200KB/s
    }
}

5.4 防爬虫与恶意请求

server {
    listen 80;
    server_name example.com;

    # ── UA 黑名单 ───────────────────────────────
    if ($http_user_agent ~* "(AhrefsBot|SemrushBot|MJ12bot|scrapbot|Python-urllib)") {
        return 403;
    }

    # ── 禁止通过代理访问 ───────────────────────
    if ($http_via ~* ".+") {
        return 403;
    }

    # ── 常见攻击路径拦截 ───────────────────────
    location ~ /\.(git|svn|hg|env|config|bak)$ {
        deny all;
        access_log off;
        log_not_found off;
    }

    # SQL 注入防护
    if ($query_string ~* "union.*select.*\(") {
        return 403;
    }

    # XSS 防护
    if ($query_string ~* "<.*>") {
        return 403;
    }
}

六、HTTPS 与 HTTP/2 优化

6.1 SSL/TLS 配置

server {
    listen 443 ssl http2;  # ✅ HTTP/2 配合 HTTPS 使用
    server_name example.com;

    # ── SSL 证书配置 ────────────────────────────
    ssl_certificate     /etc/nginx/ssl/example.com.crt;
    ssl_certificate_key /etc/nginx/ssl/example.com.key;

    # ── TLS 版本控制(禁用老旧协议)───────────────
    ssl_protocols TLSv1.2 TLSv1.3;  # ✅ 只启用 TLS 1.2 和 1.3

    # ── 加密套件(优先高性能 + 高安全)─────────────
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;

    ssl_prefer_server_ciphers on;    # 服务端套件优先级高于客户端

    # ── SSL 会话复用 ─────────────────────────────
    ssl_session_cache   shared:SSL:50m;    # 50MB 缓存,减少握手开销
    ssl_session_timeout 1d;             # 缓存有效期 1 天
    ssl_session_tickets on;             # 支持会话票据(无状态恢复)

    # ── OCSP Stapling(减少证书验证延迟)──────────
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;
}

6.2 HTTP/2 与多路复用

# HTTP/2 的核心优势:
# 1. 多路复用:一个连接并行处理多个请求(无需排队)
# 2. Header 压缩(HPACK):减少头部冗余
# 3. 服务端推送:主动推送 CSS/JS 等资源
# 4. 流量控制:按优先级分配带宽

server {
    listen 443 ssl http2;
    server_name example.com;

    # 服务端推送示例(推送关键 CSS/JS)
    location = /index.html {
        http2_push /static/css/main.css;
        http2_push /static/js/app.js;
        http2_push /static/fonts/icon.woff2;
    }
}

七、压测与监控:用数据验证优化效果

7.1 压测工具:wrk

# 安装 wrk(Linux/macOS)
# Ubuntu: apt install wrk
# macOS:  brew install wrk

# ── 基础压测:静态文件 ─────────────────────────
wrk -t12 -c400 -d30s http://127.0.0.1/index.html
# -t12 : 12 个线程
# -c400: 400 个并发连接
# -d30s: 持续 30 秒

# 输出示例:
# Running 30s test @ http://127.0.0.1/index.html
# Thread Stats   Avg      Stdev     Max   +/- Stdev
# Latency       12.34ms    5.67ms  89.23ms   85.32%
# Req/Sec       3205.56    234.12  4200.00     68.21%
# 356234 requests in 30.01s, 4.28GB read
# Socket errors: connect 0, read 0, write 0, timeout 0
# Requests/sec:  11872.34    ← 关键指标:QPS
# Transfer/sec: 146.12MB

# ── 带 Lua 脚本的压测:模拟真实用户行为 ─────────
# post.lua:每个请求带上随机用户 ID
wrk -t8 -c200 -d60s -s post.lua http://127.0.0.1/api/users

post.lua 示例:

-- post.lua:POST 请求压测脚本
wrk.method = "POST"
wrk.headers["Content-Type"] = "application/json"
wrk.body   = '{"username":"user123","action":"login"}'

7.2 Nginx 内置状态监控

http {
    # 启用 status 监控模块
    server {
        listen 80;
        server_name localhost;
        location /nginx_status {
            stub_status on;      # ✅ 开启状态监控
            access_log   off;
            allow        127.0.0.1;  # 仅本地访问
            deny         all;
        }
    }
}
# 查看状态
curl http://127.0.0.1/nginx_status

# Active connections: 291        ← 当前活跃连接数
# server accepts handled requests
#   16630948 16630948 31070465   ← 总接受数 / 总连接数 / 总请求数
# Reading: 6 Writing: 179 Waiting: 106  ← 读/写/等待状态

7.3 优化前后对比(实测数据参考)

以 4 核 CPU / 8GB 内存服务器,100KB 静态资源为例:

优化项 优化前 QPS 优化后 QPS 提升幅度
默认配置 ~3,200 基准
+ worker_processes auto + epoll ~9,800 +206%
+ sendfile + tcp_nopush + tcp_nodelay ~14,500 +48%
+ gzip 压缩(text/css/js) ~28,000 +93%
+ open_file_cache + expires 缓存 ~45,000 +61%
全部优化 + CDN 接入 ~120,000+ +167%

八、生产环境完整配置模板

# /etc/nginx/nginx.conf
user  nginx;
worker_processes  auto;
worker_cpu_affinity auto;
worker_priority  -5;
worker_rlimit_nofile 65535;
error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  10240;
    use                 epoll;
    multi_accept        on;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    # 传输优化
    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    aio                 on;
    directio            512;
    open_file_cache     max=10000 inactive=60s;
    open_file_cache_valid 30s;

    # 连接与超时
    keepalive_timeout   65;
    keepalive_requests  10000;
    client_header_timeout  10s;
    client_body_timeout    10s;
    send_timeout           10s;
    reset_timedout_connection on;

    # 请求限制
    client_max_body_size 50m;
    client_header_buffer_size 4k;
    large_client_header_buffers 4 32k;

    # Gzip 压缩
    gzip                on;
    gzip_vary           on;
    gzip_proxied       any;
    gzip_comp_level     5;
    gzip_min_length    1024;
    gzip_types text/plain text/css text/javascript application/javascript application/json application/xml image/svg+xml font/ttf font/woff;

    # 安全头
    server_tokens off;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;

    # 限流
    limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s;
    limit_conn_zone $binary_remote_addr zone=conn_limit:10m;

    # ── 上游服务器 ──────────────────────────────
    upstream backend {
        least_conn;
        server 127.0.0.1:8080 weight=3;
        server 127.0.0.1:8081 weight=2;
        server 127.0.0.1:8082 weight=1 backup;
        keepalive 32;
    }

    # ── 静态资源服务器 ───────────────────────────
    server {
        listen 80;
        server_name static.example.com;

        root /var/www/static;
        index index.html;

        # 静态资源永缓存
        location ~* \.(css|js|jpg|png|gif|ico|svg|woff|woff2|ttf|eot)$ {
            expires 1y;
            add_header Cache-Control "public, immutable";
            access_log off;
            gzip_static on;  # 优先使用预压缩文件
        }

        # HTML 不缓存
        location ~* \.html$ {
            expires -1;
        }
    }

    # ── API 反向代理 ────────────────────────────
    server {
        listen 80;
        server_name api.example.com;

        location / {
            proxy_pass         http://backend;
            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;

            # 限流
            limit_req zone=req_limit burst=20 nodelay;
            limit_conn conn_limit 5;
        }

        # 健康检查接口
        location /health {
            access_log off;
            return 200 "OK";
        }
    }
}

结语

Nginx 的性能优化是一个系统性工程,核心在于三点:减少 I/O(零拷贝、缓存、压缩)、减少连接开销(长连接复用、worker 优化)、精准控制流量(限流、安全头、防盗链)。建议按以下路径推进:

第一步:检查当前 QPS 基线(wrk 压测)
第二步:按本文配置逐项优化,每次改完压测一次
第三步:观察 Nginx status 和慢查询日志,确认优化生效
第四步:接入 Prometheus + Grafana 持续监控,长期保持最优状态

上一篇:MySQL 高级用法完全指南:从窗口函数到性能调优的实战手册 下一篇:一文讲透 Agent、RAG、Skill 与 MCP 的区别与联动

评论

评论(0)

暂无评论