Nginx 性能调优完全指南:从一次"30 万 QPS 促销 502 满天飞 CPU 跑满 30 分钟"看懂为什么默认配置远远不够

2021 年我加入一家短视频公司接手 API 网关用 Nginx 做反向代理后端 50 个微服务日常 QPS 5 万高峰 20 万第一版我用 Nginx 默认配置装好就上业务跑了半年没事直到一次促销活动流量瞬间冲到 30 万 QPS Nginx CPU 100% 大量 502 用户疯狂吐槽老板半夜把我电话打爆然后我们陆续踩了一堆坑第一种最让我傻眼 worker_processes 默认 1 单核跑死我们机器 32 核 31 核闲着改成 auto 立马翻 30 倍第二种最难缠 worker_connections 默认 1024 单 worker 最多 1024 并发 32 worker 也才 3 万不够 30 万 QPS 改成 65535 又开始 too many open files 操作系统 file descriptor 限制没改第三种最离谱我们 upstream keepalive 没配每次请求 Nginx 都要重新与后端建 TCP 连接三次握手延迟 30ms 还烧 backend 端口配置 keepalive 64 后 RPS 翻倍延迟降一半第四种最致命我们 gzip 默认关后端返回 500KB JSON Nginx 透传给客户端移动端带宽爆加载 5 秒开启 gzip 后压缩到 50KB 移动端秒开但 CPU 涨 10% 这个权衡之前没考虑第五种最莫名其妙我们 proxy_buffering 默认开后端慢响应 Nginx 等接收完才转给客户端客户端看到的延迟等于后端处理加 Nginx 缓冲流式 API 直接超时改成 off 流式才正常这种东西教科书不写我盯着这一连串问题想了很久才彻底想明白第一版错在一个根本的认知上我以为 Nginx 装好就能扛十万 QPS 默认配置够用可这个认知是错的真正能扛业务的 Nginx 是一个进程与连接模型调优加 upstream 与 keepalive 加缓冲压缩 SSL 加限流熔断加日志与监控加内核参数协同的整套工程方法论

2021 年我加入一家短视频公司 接手 API 网关 用 Nginx 做反向代理 后端 50 个微服务 日常 QPS 5 万 高峰 20 万。第一版我用 Nginx 默认配置 装好就上 业务跑了半年没事 直到一次促销活动 流量瞬间冲到 30 万 QPS Nginx CPU 100% 大量 502 用户疯狂吐槽 老板半夜把我电话打爆。然后我们陆续踩了一堆坑。第一种最让我傻眼 worker_processes 默认 1 单核跑死 我们机器 32 核 31 核闲着 改成 auto 立马翻 30 倍。第二种最难缠 worker_connections 默认 1024 单 worker 最多 1024 并发 32 worker 也才 3 万 不够 30 万 QPS 改成 65535 又开始 too many open files 操作系统 file descriptor 限制没改。第三种最离谱 我们 upstream keepalive 没配 每次请求 Nginx 都要重新与后端建 TCP 连接 三次握手延迟 30ms 还烧 backend 端口 配置 keepalive 64 后 RPS 翻倍 延迟降一半。第四种最致命 我们 gzip 默认关 后端返回 500KB JSON Nginx 透传给客户端 移动端带宽爆 加载 5 秒 开启 gzip 后压缩到 50KB 移动端秒开 但 CPU 涨 10% 这个权衡之前没考虑。第五种最莫名其妙 我们 proxy_buffering 默认开 后端慢响应 Nginx 等接收完才转给客户端 客户端看到的延迟 = 后端处理 + Nginx 缓冲 流式 API 直接超时 改成 off 流式才正常 这种东西教科书不写。我盯着这一连串问题想了很久才彻底想明白第一版错在一个根本的认知上我以为 Nginx 装好就能扛十万 QPS 默认配置够用 可这个认知是错的真正能扛业务的 Nginx 是一个 进程与连接模型调优 加 upstream 与 keepalive 加 缓冲压缩 SSL 加 限流熔断 加 日志与监控 加 内核参数协同 的整套工程方法论 任何一环没做都可能让你的网关 502 满天飞 CPU 跑满 后端被打挂本文从头梳理 Nginx 性能调优的工程要点 worker 怎么配 keepalive 怎么开 缓冲怎么调 gzip 怎么平衡 限流怎么设 内核怎么协同 以及一些把 Nginx 做扎实要避开的工程坑

问题背景:为什么 Nginx 默认配置不够

很多人以为 Nginx 是高性能代表 装好就行 实际上 Nginx 默认配置是为了通用兼容性 不是为了极限性能。默认 worker_processes 1 默认 worker_connections 1024 默认无 upstream keepalive 默认 gzip 关 这些都是上线必改的项目 不改就是大马拉小车 32 核机器只用 1 核。问题的根源在于:

  • 进程模型决定并发上限:worker_processes 必须等于 CPU 核数 worker_connections 必须 6 万+ 不然并发上不去。
  • upstream keepalive 节省 50% 后端开销:不开启每个请求都三次握手 后端端口耗尽 backend 也累。
  • gzip 是带宽与 CPU 的权衡:大 JSON 必须开 节省 90% 带宽 但增加 10% CPU。
  • proxy_buffering 在流式场景必关:SSE WebSocket 长轮询 开 buffering 直接超时。
  • 限流是网关的最后底线:limit_req limit_conn 必配 不配后端被刷挂。
  • 内核参数必须协同:net.core.somaxconn fs.file-max sysctl 不调 Nginx 配再大也没用。

一 进程与连接模型:Nginx 性能的根基

Nginx 是 master + worker 多进程模型 worker 数量与连接数量决定并发上限。默认 worker_processes 1 单核跑 直接浪费 32 核机器 必须改成 auto 让 Nginx 跑满所有 CPU。worker_connections 默认 1024 单 worker 最多 1024 并发 现代服务必须改大。

# 1 worker 配置 nginx.conf 顶部
user www-data;
worker_processes auto;  # 等于 CPU 核数 默认 1 是大坑
worker_rlimit_nofile 102400;  # 单 worker 最大文件描述符

# 2 events 块 连接模型
events {
    use epoll;  # Linux 高性能事件模型 Linux 上默认 epoll
    worker_connections 65535;  # 单 worker 最大连接数
    multi_accept on;  # worker 一次 accept 多个新连接 高并发友好
    accept_mutex off;  # Linux 3.9+ SO_REUSEPORT 后不需要 mutex
}

# 3 worker 与 CPU 亲和 减少上下文切换
# 32 核机器
worker_processes 32;
worker_cpu_affinity auto;  # 自动绑定 推荐
# 或手动绑定 worker 0 绑核 0 worker 1 绑核 1
# worker_cpu_affinity 0000000000000000000000000000001
#                     0000000000000000000000000000010
#                     ...

# 4 worker_rlimit_nofile 必须大于 worker_connections
# 否则 worker 报 too many open files
# 同时要改操作系统 ulimit -n
# /etc/security/limits.conf
# * soft nofile 102400
# * hard nofile 102400

worker 数量不是越多越好 等于 CPU 核数最佳 多了反而上下文切换开销大。worker_connections 也不是越大越好 受限于 worker_rlimit_nofile 操作系统 file-max 内存等。算总连接数 = worker_processes * worker_connections 一台 32 核 65535 连接 = 200 万并发理论上限。

# 5 操作系统配套调优 /etc/sysctl.conf

# 文件描述符
fs.file-max = 1000000
fs.nr_open = 1000000

# 网络相关
net.core.somaxconn = 65535          # listen backlog 默认 128 太小
net.core.netdev_max_backlog = 65535 # 网卡 backlog
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_tw_reuse = 1           # TIME_WAIT 重用 高并发必开
net.ipv4.tcp_fin_timeout = 15        # FIN_WAIT 超时 默认 60s
net.ipv4.ip_local_port_range = 1024 65535  # 本地端口范围
net.ipv4.tcp_max_tw_buckets = 1048576

# 内存相关
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216

# 应用后必须 sysctl -p 生效
# 不调内核参数 Nginx 配再大也是空谈

# 6 ulimit 检查
ulimit -n          # 看当前用户最大文件描述符
cat /proc/sys/fs/file-max  # 看系统总上限
ss -s              # 看当前连接数统计

进程与连接模型的工程经验 worker_processes=auto worker_connections=65535 multi_accept=on 是必改三项 worker_rlimit_nofile 要 100K+ 同时改操作系统 ulimit 与 sysctl 内核参数 才能让 Nginx 跑满硬件 这套配置能让 32 核机器单机扛 100 万并发不出错。我们公司从默认配置改成这套 单台 Nginx QPS 从 3 万涨到 30 万 节省了一半的机器。

二 Upstream Keepalive:省 50% 后端开销

Nginx 与后端的连接默认每次请求都新建 TCP 三次握手 + TLS 握手 30ms 起步 还烧 backend 端口。开启 upstream keepalive 让 Nginx 复用与后端的 TCP 连接 RPS 翻倍 延迟降一半。这是 Nginx 调优最容易省力的一项。

# 1 配置 upstream keepalive
upstream backend_api {
    server 10.0.1.10:8080 max_fails=3 fail_timeout=30s;
    server 10.0.1.11:8080 max_fails=3 fail_timeout=30s;
    server 10.0.1.12:8080 max_fails=3 fail_timeout=30s;

    # 关键 keepalive 配置
    keepalive 64;              # 每个 worker 与 upstream 保持 64 个空闲连接
    keepalive_requests 10000;  # 单连接最大请求数 默认 100 太小
    keepalive_timeout 60s;     # 空闲连接最大保持时间
}

# 2 必须配合的几个指令 location 块里
location /api/ {
    proxy_pass http://backend_api;

    # HTTP 1.1 才支持 keepalive
    proxy_http_version 1.1;

    # 清空 Connection header 默认 close 会关连接
    proxy_set_header 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_set_header X-Forwarded-Proto $scheme;

    # 后端连接超时
    proxy_connect_timeout 5s;
    proxy_send_timeout 30s;
    proxy_read_timeout 30s;
}

# 3 keepalive 与负载均衡算法配合
upstream backend_api {
    least_conn;  # 最少连接 比默认 round-robin 更适合 keepalive
    server 10.0.1.10:8080;
    server 10.0.1.11:8080;
    server 10.0.1.12:8080;
    keepalive 64;
    keepalive_requests 10000;
}

# 4 不同后端 keepalive 配置
upstream static_backend {
    server 10.0.2.10:80;
    keepalive 16;       # 静态服务低 keepalive
}

upstream api_backend {
    server 10.0.3.10:8080;
    keepalive 128;      # 高频 API 高 keepalive
}

upstream db_proxy {
    server 10.0.4.10:6379;
    keepalive 32;       # Redis 连接
}

keepalive 数量怎么定有个经验公式 keepalive * worker_processes 大于等于 QPS / TPS 比如 QPS 1 万 每请求 50ms 那 TPS 200 worker 32 keepalive 64 总能保持 2048 长连接 大于 200 够用且有富余。

# 5 验证 keepalive 是否生效

# 5.1 nginx -V 看是否编译 keepalive 模块
# 默认 1.4+ 都支持

# 5.2 查看 upstream 连接状态 需要 stub_status 模块
location = /nginx_status {
    stub_status on;
    allow 127.0.0.1;
    deny all;
}
# curl localhost/nginx_status
# Active connections: 30000
# server accepts handled requests
#  10000000 10000000 50000000
# Reading: 100 Writing: 500 Waiting: 29400
# 大量 Waiting 说明 keepalive 在工作

# 5.3 后端看 TCP 连接
# 后端 ss -tan | grep ESTAB | wc -l
# 如果数量稳定且不与请求数线性增长 说明复用生效

# 6 keepalive 的坑 backend 必须支持
# 后端 Tomcat 必须配置
#   
# 后端 Nginx 必须配置 keepalive_timeout
# 后端 Node.js Express server.keepAliveTimeout = 65000
# 否则 backend 主动关连接 keepalive 失效

# 7 keepalive 与连接池监控
upstream backend_api {
    server 10.0.1.10:8080;
    keepalive 64;
    keepalive_requests 10000;
    # nginx-plus 版本可以看更详细统计 开源版只能靠 stub_status
}

Upstream Keepalive 的工程经验 必须开 keepalive 64-256 keepalive_requests 10000 keepalive_timeout 60s proxy_http_version 1.1 proxy_set_header Connection 空 这五项必备 backend 也要配 keepalive 不然 Nginx 单方面是无效的 验证用 stub_status 看 Waiting 数 这套组合能让 P99 延迟从 200ms 降到 50ms RPS 翻倍 backend 端口压力降 80%。我们公司一次 keepalive 优化 backend 服务器从 50 台降到 30 台 月省 20 万机器费用。

三 缓冲压缩与 SSL:细节决定吞吐

缓冲与压缩是 Nginx 的重要功能 但默认参数不一定适合你的场景。gzip 默认关 流式场景 buffering 必须关 SSL 不调优握手吃 CPU 这些细节调好 吞吐能再翻倍。

# 1 gzip 压缩配置
http {
    gzip on;
    gzip_vary on;            # 加 Vary: Accept-Encoding header
    gzip_min_length 1024;    # 小于 1KB 不压缩 压缩成本大于收益
    gzip_comp_level 5;       # 1-9 5 是平衡点 9 太耗 CPU
    gzip_proxied any;        # 代理请求也压缩 默认 off
    gzip_types
        text/plain
        text/css
        text/xml
        text/javascript
        application/json
        application/javascript
        application/xml
        application/atom+xml
        application/rss+xml
        application/xml+rss
        image/svg+xml;
    # 注意 image/jpeg image/png 别压缩 本身就是压缩格式

    # 2 静态文件用 gzip_static 预压缩
    gzip_static on;
    # 配合在文件系统放 file.html 与 file.html.gz
    # Nginx 优先返回 .gz 文件 节省 CPU
}

# 3 proxy buffering 缓冲配置
location /api/ {
    proxy_pass http://backend;

    # 默认 buffering on 后端慢响应 Nginx 接收完才转客户端
    # 适合大多数场景 减轻后端连接占用
    proxy_buffering on;
    proxy_buffer_size 16k;     # response header buffer
    proxy_buffers 8 16k;       # response body buffer 8 * 16k = 128k
    proxy_busy_buffers_size 32k;
    proxy_temp_file_write_size 32k;
}

# 4 流式场景必须关 buffering
location /api/stream {
    proxy_pass http://backend;
    proxy_buffering off;       # 立即转发 不缓冲
    proxy_cache off;           # 不缓存
    proxy_read_timeout 24h;    # SSE 可能长连接
    proxy_send_timeout 24h;
    chunked_transfer_encoding on;
}

location /api/websocket {
    proxy_pass http://backend;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_buffering off;
    proxy_read_timeout 24h;
}

gzip 不是越激进越好 comp_level 9 CPU 占用比 5 高 50% 但压缩率只多 5% 不划算。流式场景 SSE WebSocket 长轮询 proxy_buffering 必须关 不然客户端看到的延迟会很高 等于客户端等 Nginx 把整个流接完才看到。

# 5 SSL 调优
server {
    listen 443 ssl http2 reuseport;
    server_name api.example.com;

    # 证书
    ssl_certificate /etc/nginx/ssl/api.crt;
    ssl_certificate_key /etc/nginx/ssl/api.key;

    # SSL session 缓存 减少握手 关键
    ssl_session_cache shared:SSL:50m;  # 50MB 缓存约 200000 session
    ssl_session_timeout 1d;             # session 缓存时间
    ssl_session_tickets off;            # tickets 安全风险 关掉

    # 协议与套件 安全且性能好
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
    ssl_prefer_server_ciphers off;  # TLS 1.3 推荐 off

    # OCSP stapling 减少客户端验证延迟
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 1.1.1.1 8.8.8.8 valid=60s;

    # DH 参数 用 2048 平衡安全与性能
    ssl_dhparam /etc/nginx/ssl/dhparam.pem;
    # 生成 openssl dhparam -out dhparam.pem 2048

    # HSTS 强制 HTTPS
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    # 性能 buffer 调优
    ssl_buffer_size 4k;  # 默认 16k 改小减少 TTFB

    location / {
        proxy_pass http://backend;
    }
}

# 6 http2 启用 长连接复用更高效
listen 443 ssl http2;
# 注意 http2 与 keepalive 不冲突 但 http2 内部已经多路复用
# 实测 http2 + keepalive 比 http1.1 + keepalive 还快 20%

缓冲压缩 SSL 的工程经验 gzip on comp_level 5 types 包含 json xml js css svg 不要漏 流式场景必关 proxy_buffering 不然客户端体验差 SSL session_cache 50m 1d HSTS 必开 http2 必开 这套配置能让大请求带宽降 90% TTFB 降 50% SSL 握手成本降 80%。我们公司一次 gzip 调优 总出口带宽从 8Gbps 降到 1.5Gbps CDN 月省 8 万。

四 限流与熔断:守住后端最后底线

网关必须做限流 不限流后端被打挂只是时间问题。Nginx 提供 limit_req 限速 limit_conn 限并发 配合自定义脚本可以做熔断 这是上线硬规范。

# 1 limit_req 限流 基于 leaky bucket 漏桶算法
http {
    # 定义限流 zone 10m 内存约 16 万 IP 状态
    limit_req_zone $binary_remote_addr zone=api_per_ip:10m rate=10r/s;
    limit_req_zone $server_name zone=api_global:10m rate=10000r/s;

    server {
        location /api/ {
            # IP 维度 每秒 10 请求 突发 20
            limit_req zone=api_per_ip burst=20 nodelay;

            # 全局维度 每秒 1 万请求 突发 5 千
            limit_req zone=api_global burst=5000 nodelay;

            # 超限响应
            limit_req_status 429;
            limit_req_log_level warn;

            proxy_pass http://backend;
        }
    }
}

# 2 limit_conn 限并发连接
http {
    limit_conn_zone $binary_remote_addr zone=conn_per_ip:10m;
    limit_conn_zone $server_name zone=conn_global:10m;

    server {
        location /api/ {
            limit_conn conn_per_ip 100;     # 单 IP 最多 100 并发
            limit_conn conn_global 10000;   # 全局最多 1 万并发
            limit_conn_status 503;
            proxy_pass http://backend;
        }
    }
}

# 3 限流的几个进阶用法

# 3.1 不同 location 不同限流
location /api/heavy/ {
    limit_req zone=api_per_ip burst=5 nodelay;  # 重接口低限
    proxy_pass http://backend;
}

location /api/light/ {
    limit_req zone=api_per_ip burst=50 nodelay;  # 轻接口高限
    proxy_pass http://backend;
}

# 3.2 白名单不限流
geo $limit {
    default 1;
    10.0.0.0/8 0;       # 内网不限
    192.168.0.0/16 0;
    100.64.0.0/10 0;
}
map $limit $limit_key {
    0 "";
    1 $binary_remote_addr;
}
limit_req_zone $limit_key zone=api_with_whitelist:10m rate=10r/s;

# 3.3 按 user_id 限流 而非 IP
limit_req_zone $http_x_user_id zone=api_per_user:10m rate=100r/s;
location /api/ {
    if ($http_x_user_id = '') {
        return 401;
    }
    limit_req zone=api_per_user burst=200 nodelay;
    proxy_pass http://backend;
}

限流参数怎么定有几个经验 rate 设为后端能承受的 70% 留 30% 余量给突发 burst 设为 rate 的 2-5 倍 nodelay 让突发不排队直接拒绝 否则用户感受卡顿 limit_conn 设为单实例能扛的并发数 防止单用户耗尽连接池。

# 4 熔断 用 max_fails fail_timeout
upstream backend {
    server 10.0.1.10:8080 max_fails=3 fail_timeout=30s;
    server 10.0.1.11:8080 max_fails=3 fail_timeout=30s;
    server 10.0.1.12:8080 max_fails=3 fail_timeout=30s;
    # 单台 30 秒内失败 3 次 标记 unavailable 30 秒
    keepalive 64;
}

# 5 备用 upstream 主挂了切备
upstream backend {
    server 10.0.1.10:8080;
    server 10.0.1.11:8080;
    server 10.0.2.10:8080 backup;  # 主全挂了才用
    server 10.0.2.11:8080 backup;
}

# 6 主动健康检查 nginx-plus 或 lua 实现
# 开源版用 proxy_next_upstream 被动健康检查
location /api/ {
    proxy_pass http://backend;
    proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
    proxy_next_upstream_timeout 10s;
    proxy_next_upstream_tries 3;
}

# 7 错误页面统一处理
error_page 500 502 503 504 /50x.html;
location = /50x.html {
    return 503 '{"error":"service temporarily unavailable","retry_after":30}';
    add_header Content-Type application/json;
    add_header Retry-After 30;
}

error_page 429 /429.json;
location = /429.json {
    return 429 '{"error":"too many requests","retry_after":1}';
    add_header Content-Type application/json;
    add_header Retry-After 1;
}

限流熔断的工程经验 limit_req 必配 IP 维度 + 全局维度双层防护 burst nodelay 不要排队 内网白名单不限流 重接口与轻接口不同限流 max_fails fail_timeout 实现被动熔断 配合 proxy_next_upstream 自动切换 错误页面统一 JSON 格式带 Retry-After 这套组合能让后端永远不被打挂 用户看到友好错误而非 502 502 502。我们公司一次促销 没限流前后端被 30 万 QPS 打挂 加 limit_req 后再来 50 万 QPS 多余的直接 429 后端稳如老狗。

[mermaid]flowchart TD
A[客户端请求] --> B[Nginx 入口]
B --> C{IP 限流 limit_req}
C -->|超限| D[429 返回]
C -->|放行| E{并发限流 limit_conn}
E -->|超限| F[503 返回]
E -->|放行| G{SSL 握手}
G --> H{gzip 解压请求}
H --> I[upstream 负载均衡]
I --> J{health check}
J -->|健康| K[keepalive 长连接复用]
J -->|不健康| L[切下一个 upstream]
L --> J
K --> M[backend 处理]
M --> N[proxy_buffering]
N -->|普通 API| O[完整缓冲]
N -->|流式 SSE| P[立即转发]
O --> Q[gzip 压缩响应]
P --> Q
Q --> R[返回客户端]

五 日志与监控:发现问题先于用户

不监控的 Nginx 就是黑盒 你不知道 QPS 多少 延迟多少 错误率多少 哪些 URL 慢 哪些 IP 在攻击 必须日志规范 + 监控埋点。一旦出问题没监控就是抓瞎 等用户来投诉。

# 1 access log 自定义格式 带关键指标
log_format detailed escape=json '{'
    '"time":"$time_iso8601",'
    '"remote_addr":"$remote_addr",'
    '"request_method":"$request_method",'
    '"request_uri":"$request_uri",'
    '"status":$status,'
    '"body_bytes_sent":$body_bytes_sent,'
    '"request_time":$request_time,'
    '"upstream_addr":"$upstream_addr",'
    '"upstream_response_time":"$upstream_response_time",'
    '"upstream_status":"$upstream_status",'
    '"http_referer":"$http_referer",'
    '"http_user_agent":"$http_user_agent",'
    '"http_x_forwarded_for":"$http_x_forwarded_for",'
    '"request_id":"$request_id",'
    '"server_name":"$server_name",'
    '"ssl_protocol":"$ssl_protocol",'
    '"ssl_cipher":"$ssl_cipher"'
'}';

access_log /var/log/nginx/access.log detailed buffer=32k flush=5s;

# 2 error log 分级别记录
error_log /var/log/nginx/error.log warn;

# 3 日志切割 daily 防止文件爆
# 使用 logrotate
# /etc/logrotate.d/nginx
# /var/log/nginx/*.log {
#     daily
#     rotate 30
#     compress
#     missingok
#     notifempty
#     create 0640 www-data adm
#     postrotate
#         [ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
#     endscript
# }

# 4 stub_status 模块开启监控端点
server {
    listen 127.0.0.1:8080;
    location = /nginx_status {
        stub_status on;
        access_log off;
        allow 127.0.0.1;
        deny all;
    }
}

# 5 用 nginx-vts-module 或 nginx-prometheus-exporter 暴露 prometheus 指标
# nginx-prometheus-exporter
# docker run -p 9113:9113 nginx/nginx-prometheus-exporter:latest \
#   -nginx.scrape-uri=http://localhost:8080/nginx_status

# Prometheus 抓取
# scrape_configs:
#   - job_name: nginx
#     static_configs:
#       - targets: ['localhost:9113']

# 6 关键指标告警规则
# nginx_connections_active > 50000 报警
# nginx_http_requests_total rate > 100000/s 报警
# nginx_connections_waiting / active > 0.5 看 keepalive 是否健康

access log 不是越详细越好 写日志也是性能开销 用 buffer=32k flush=5s 异步刷盘 减少 IO 压力。high-traffic 站点可以 access_log off 或者只采样 1% 日志 否则单 Nginx 日志一天 100GB 磁盘扛不住。

# 7 实时分析日志的几个工具

# 7.1 GoAccess 实时 dashboard
goaccess /var/log/nginx/access.log -o /var/www/html/report.html \
    --log-format=COMBINED --real-time-html

# 7.2 awk 统计 top URL
awk '{print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

# 7.3 找慢请求
jq 'select(.request_time > 1)' /var/log/nginx/access.log | head -20

# 7.4 找 5xx 错误
jq 'select(.status >= 500)' /var/log/nginx/access.log | head -20

# 7.5 找特定 IP 的请求
jq 'select(.remote_addr == "1.2.3.4")' /var/log/nginx/access.log

# 7.6 统计 QPS
tail -f /var/log/nginx/access.log | jq -r '.time' | uniq -c

日志与监控的工程经验 access log 用 JSON 格式带 request_time upstream_response_time request_id 字段 buffer 异步刷盘 用 stub_status 加 prometheus exporter 暴露指标 关键指标 active connections requests rate 5xx ratio 告警 日志切割 logrotate 防爆 高流量站点采样 1% 不要全量 这套监控能让你在用户投诉前发现问题。我们公司一次 backend 慢响应 监控发现 P99 飙升立刻定位 用户还没反应过来就修了 SLA 没破线。

六 Nginx 的工程坑:那些教科书没写的

讲完原理来说几个真实生产里踩过的坑。第一个坑是 nginx -s reload 不是无损 reload 时旧 worker 处理完请求才退出 但新连接会被新 worker 接管 长连接客户端无感 但短连接突发流量时 reload 可能丢几个连接 关键时刻用 nginx -t 验证后再 reload 别盲目操作。第二个坑是 location 匹配顺序 = 精确 ^~ 前缀 ~ 正则 ~* 不区分大小写正则 普通前缀 这个顺序错了就匹配到错的 location 我们踩过 location /api 与 location ~ \.php$ 优先级冲突导致 PHP 文件被代理而非执行。第三个坑是 try_files 与 rewrite 容易死循环 一定先 nginx -t 看配置再上 我们一次 rewrite ^/old/(.*)$ /new/$1 last 没考虑 new 路径也命中规则 死循环 502 满天飞。第四个坑是 SSL 证书更新 不能直接覆盖文件 Nginx 不会自动 reload 需要 nginx -s reload Let's Encrypt 自动续期要配 hooks 我们公司一次证书到期没 reload 用户访问 SSL 错误半小时。第五个坑是 大文件上传必须调 client_max_body_size 默认 1MB 用户上传图片就 413 配合 client_body_buffer_size proxy_request_buffering 否则大文件内存爆。

关键概念速查

概念 含义 工程价值
worker_processes worker 数 必等 CPU 核数
worker_connections 单 worker 连接 65535 上限
upstream keepalive 后端长连接 RPS 翻倍延迟减半
proxy_buffering 响应缓冲 流式必关
gzip_comp_level 压缩等级 1-9 5 是平衡点
SSL session cache 会话缓存 握手成本降 80%
limit_req 速率限流 守住后端底线
limit_conn 并发限流 防止单 IP 耗资源
max_fails fail_timeout 被动熔断 自动剔除故障
stub_status 状态端点 监控基础

避坑清单

  1. worker_processes auto worker_connections 65535 multi_accept on 必改。
  2. 同步调整操作系统 ulimit -n 与 sysctl 内核参数 不然白配。
  3. upstream keepalive 64+ keepalive_requests 10000 proxy_http_version 1.1 必备。
  4. gzip on 但 image/jpeg image/png 别压缩 已经是压缩格式。
  5. 流式场景 SSE WebSocket 必须 proxy_buffering off 否则超时。
  6. SSL session_cache 50m 1d HSTS http2 必开 性能与安全双赢。
  7. limit_req IP 维度 + 全局维度双层限流 burst nodelay 不排队。
  8. max_fails fail_timeout 实现被动熔断 配合 proxy_next_upstream 切换。
  9. access log 用 JSON 格式异步刷盘 高流量站点采样不要全量。
  10. reload 前必 nginx -t 验证配置 location 顺序与 rewrite 死循环都常见。

总结

Nginx 性能调优这事 很多人的直觉是 装好就行 默认配置 Nginx 这么有名肯定够用。这其实是把 我能让 Nginx 跑起来 和 我能让 Nginx 单机扛 30 万 QPS 不 502 不 OOM 不被打挂 混为一谈。前者是会装 Nginx 后者是懂 Nginx 工程。中间隔着的是 进程模型 keepalive 缓冲压缩 SSL 限流熔断 监控调优 整整一套工程方法论。

从装好到能扛 你需要做的事远不止 apt install nginx。你要懂 worker 怎么配 keepalive 怎么开 gzip 怎么平衡 buffering 怎么关 SSL 怎么调优 limit_req 怎么设 内核参数怎么协同 日志怎么监控。每一项单独看都不复杂 但它们组合在一起 才是一个能扛百万并发的网关。少任何一项 都可能让你的 Nginx 502 满天飞 CPU 跑满 后端被打挂 半夜被电话叫醒。

我经常用一个比喻来理解 Nginx 它有点像一家大酒店的前台。worker 是前台员工的数量 默认 1 个员工 32 个客人都得排队 改成 auto 32 个员工同时接待。keepalive 是与各餐厅厨房保持电话不挂 避免每次点单都重新拨号 30ms 三次握手对应的就是这个开销。gzip 是把客人要的资料压缩后递出去 大文档节省纸张但要多花点时间打包。proxy_buffering 是先把厨房做好的菜全部端到前台再送给客人 大多数客人不在乎 但点流食的客人等不及 必须做一道端一道。SSL 是给每位 VIP 客人验身份 第一次验完发个临时通行证 后面直接刷证不用再验 这就是 session cache。limit_req 是门口保安每秒只放 10 个客人 多了就排队或拒绝 防止厨房被挤爆。监控是大堂经理拿着监视屏 哪个餐厅排队最长哪个上菜慢一眼就知道。你不能因为前台看起来简单就只配一个员工不配电话不配压缩机不配监控 这才是一整套酒店运营。

这套架构最难的地方在于 它的复杂度在低流量阶段几乎完全暴露不了。你 1000 QPS 单 worker 默认 buffer 默认 gzip 关 一切看起来都好。但真正生产 30 万 QPS 各种 SSE 流式 各种 WebSocket 各种慢后端 各种攻击流量 各种证书更新 你才发现 99% 的复杂度都在 那 1% 的工程细节里 worker 没配 keepalive 没开 buffering 关不掉 限流没设 监控没埋。建议任何想做严肃 Nginx 调优的运维 一定要做压测 用 wrk 或 ab 模拟 5 倍峰值流量 跑一小时 看 CPU 看延迟看错误率 任何指标不达标继续调 千万别只看默认上线 那只是 Nginx 调优的冰山一角 真正生产的复杂度藏在水下 90%。

—— 别看了 · 2026
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理 邮箱1846861578@qq.com。
技术教程

LangChain Agent 工程化完全指南:从一次"Agent 死循环 12 次调用烧 0.5 美金一查"看懂为什么写 5 个 tool 远远不够

2026-5-24 16:52:41

技术教程

Stable Diffusion 文生图工程化完全指南:从一次"运营生成米老鼠营销图法务找上门"看懂为什么 pip install 远远不够

2026-5-24 17:04:11

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索