Nginx 性能调优清单:worker、缓冲区与 keepalive 的最佳实践

为什么你的 Nginx 默认配置需要调优?

刚装好的 Nginx,用起来似乎也没问题——直到某天流量突然上来了。

页面打开变慢、日志里频繁出现 502、服务器 CPU 没怎么涨但连接数已经爆了。翻一遍 nginx.conf,发现几乎所有参数都是出厂默认值:worker_processes 1worker_connections 512、缓冲区全部注释着。

默认配置是 Nginx 面向”能用”做出的妥协,不是面向”好用”的承诺。一台 8 核 16G 的云服务器,如果 worker 还是 1,相当于 7 个核在睡觉;缓冲区太小,每个请求都会触发磁盘 I/O;keepalive 没开,TCP 握手反复重建。

这篇文章给你一份可直接落地的 Nginx 性能调优清单,覆盖 worker 进程、缓冲区、keepalive、Gzip 压缩四大模块,最后用压测数据验证优化效果。无论你是在 Hostease 全能型主机 上跑 WordPress,还是在自建服务器上部署微服务,这些调优思路都适用。

调优之前,先明确一个前提:Nginx 的性能瓶颈通常不在 CPU,而在连接管理和 I/O。理解这一点,才能抓住调优的重点。

第一章:worker_processes 与 worker_connections

初次接触 Nginx 配置?建议先阅读 VPS 使用教程,确保服务器基础环境就绪。

worker_processes 设多少合适?

worker_processes 控制 Nginx 启动多少个工作进程。每个 worker 是单线程的,进程之间互相独立,不存在锁竞争。这是 Nginx 高性能的基础架构设计。

调优原则很简单:

  • CPU 密集型(静态文件服务):设为 CPU 核心数
  • IO 密集型(反向代理、PHP-FPM):设为 CPU 核心数的 1.5~2 倍
  • 偷懒方案:直接设 auto,让 Nginx 自动检测
# /etc/nginx/nginx.conf
worker_processes auto;  # 自动匹配 CPU 核心数
worker_rlimit_nofile 65535;  # 提高每个 worker 的文件描述符上限

worker_rlimit_nofile 这个参数经常被忽略。它设置每个 worker 进程能打开的最大文件描述符数量。如果你的服务器承载高并发,这个值必须大于 worker_connections,否则会报 too many open files 错误。

worker_connections 到底限制了什么?

每个 worker 能同时处理的连接数。它直接决定了 Nginx 的最大并发能力:

最大并发连接 = worker_processes × worker_connections

如果 Nginx 作为反向代理,每个客户端请求会占用 2 个连接(一个客户端到 Nginx,一个 Nginx 到后端),所以实际最大并发要除以 2。这意味着如果你的 worker_connections 设为 1024,实际只能同时服务 512 个客户端请求。

events {
    worker_connections 10240;  # 每个 worker 最多 10240 个连接
    multi_accept on;           # 一次 accept 多个新连接
    use epoll;                 # Linux 下最高效的事件模型
}

multi_accept on 让 worker 一次 accept 多个新连接,而不是一次只 accept 一个。在高并发场景下,这个配置能显著减少连接建立的延迟。

use epoll 是 Linux 2.6+ 内核推荐的事件驱动模型,相比传统的 selectpoll,epoll 在处理大量并发连接时性能优势明显。

别忘了检查系统层面的文件描述符限制:

# 查看当前限制
ulimit -n

# 临时修改
ulimit -n 65535

# 永久修改 /etc/security/limits.conf
* soft nofile 65535
* hard nofile 65535

修改完 limits.conf 后,需要重新登录 SSH 会话才能生效。可以用 ulimit -n 验证是否已经更新。

第二章:缓冲区配置

缓冲区是 Nginx 性能调优中最容易被忽视、也最容易出效果的部分。合理的缓冲区配置能减少磁盘 I/O,提高请求处理速度。

客户端请求缓冲区

Nginx 接收客户端请求时,会把请求体暂存在缓冲区里。如果缓冲区放不下,才会写入临时文件——这意味着磁盘 I/O,而磁盘 I/O 是性能杀手。

http {
    client_body_buffer_size 16k;      # 请求体缓冲区,一般 8k~32k
    client_header_buffer_size 1k;     # 请求头缓冲区
    large_client_header_buffers 4 8k; # 大请求头的缓冲区数量和单个大小
    client_max_body_size 50m;         # 允许的最大上传文件大小
}

client_body_buffer_size 的大小应该根据你的应用来定。如果你的网站有文件上传功能,可以适当增大到 128k 或 256k。但如果你的 API 请求体都很小(比如 JSON 数据),16k 就足够了。

large_client_header_buffers 用于处理较大的请求头,比如携带长 Cookie 或复杂 Authorization 头的请求。设置为 4 8k 意味着最多 4 个 8k 的缓冲区,总共 32k。

代理缓冲区(proxy_buffer)

Nginx 作为反向代理时,会先把后端响应读入缓冲区,再转发给客户端。缓冲区太小会导致频繁写入临时文件,这会显著增加延迟。

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

        proxy_buffering on;                    # 开启代理缓冲
        proxy_buffer_size 4k;                  # 第一部分响应(header)的缓冲区
        proxy_buffers 8 16k;                   # 8 个 16k 的缓冲区
        proxy_busy_buffers_size 32k;           # 繁忙时可向客户端发送的缓冲区大小
        proxy_temp_file_write_size 64k;        # 临时文件写入块大小
    }
}

proxy_buffer_size 专门用于接收后端响应的第一部分(通常是响应头)。这个值一般设为 4k 就够了,但如果你的后端返回很大的响应头(比如包含很多 Set-Cookie),可以增大到 8k 或 16k。

proxy_buffers 的格式是 数量 单个大小。总缓冲区大小 = 数量 × 单个大小。设置为 8 16k 意味着总共有 128k 的缓冲区来接收后端响应体。

FastCGI 缓冲区

如果你用 Nginx + PHP-FPM,FastCGI 缓冲区的配置直接影响 PHP 页面的响应速度:

location ~ \.php$ {
    fastcgi_pass unix:/run/php/php8.2-fpm.sock;
    fastcgi_buffering on;
    fastcgi_buffer_size 16k;
    fastcgi_buffers 16 16k;
    fastcgi_busy_buffers_size 32k;
}

PHP 页面的响应通常比纯静态文件大得多,所以 FastCGI 缓冲区应该比 proxy_buffer 更大一些。16 16k 意味着总共 256k 的缓冲区,这对于大多数 PHP 应用(WordPress、Drupal 等)已经足够了。

如果你使用的是 Hostease 的主机产品,面板通常已经预设了合理的缓冲区默认值,但理解这些参数的含义仍然是必要的——因为你了解自己的应用,才能做出最适合的调整。

第三章:keepalive 超时与连接复用

如果你同时运行 WordPress 站点,WordPress 托管方案 中包含了 Nginx 与 PHP-FPM 的优化预设配置。

HTTP/1.0 默认每个请求都要新建 TCP 连接,HTTP/1.1 才有了 keep-alive 的概念。但 Nginx 默认的 keepalive 配置非常保守,调优空间很大。

客户端侧 keepalive

http {
    keepalive_timeout 65s;    # 客户端 keepalive 超时时间
    keepalive_requests 1000;  # 一个 keepalive 连接上最多处理多少个请求
}
  • keepalive_timeout 设得太短,连接频繁断开重建;设得太长,会占用大量空闲连接,浪费服务器资源。
  • keepalive_requests 默认 1000,对大多数站点足够。如果你的页面有大量 AJAX 请求,可以适当增大到 2000 或 3000。

上游(upstream)keepalive

如果你的 Nginx 连接后端服务(PHP-FPM、Node.js、Java),一定要配置 upstream 的 keepalive:

upstream backend {
    server 127.0.0.1:8080;
    server 127.0.0.1:8081;

    keepalive 32;               # 每个 worker 保持 32 个空闲长连接
    keepalive_requests 1000;
    keepalive_timeout 60s;
}

server {
    location /api/ {
        proxy_pass http://backend;
        proxy_http_version 1.1;              # 必须使用 HTTP/1.1
        proxy_set_header Connection "";       # 清除 Connection: close
    }
}

关键点:必须显式设置 proxy_http_version 1.1 和清除 Connection 头,否则 keepalive 不生效。这是因为 HTTP/1.0 默认是短连接,而 Nginx 的 proxy_set_header Connection "" 会告诉后端不要关闭连接。

keepalive 32 的含义是每个 worker 进程保持 32 个空闲长连接到后端。这个值应该根据你的后端服务能力和并发量来调整。如果后端是 PHP-FPM,建议设为 16~32;如果是 Node.js 或 Java 服务,可以设为 64~128。

第四章:Gzip 压缩、静态文件缓存与日志优化

启用 Gzip 压缩

开启 Gzip 可以大幅减少传输体积,尤其对 HTML、CSS、JS、JSON 效果显著:

http {
    gzip on;
    gzip_vary on;                    # 添加 Vary: Accept-Encoding 头
    gzip_proxied any;                # 代理请求也压缩
    gzip_comp_level 4;               # 压缩级别 1~9,推荐 4~6
    gzip_min_length 256;             # 小于 256 字节不压缩
    gzip_types
        text/plain
        text/css
        text/javascript
        application/json
        application/javascript
        application/xml
        application/rss+xml
        image/svg+xml;
}

压缩级别(gzip_comp_level)从 1 到 9,级别越高压缩率越好但 CPU 开销也越大。测试表明,级别 4 和级别 9 的压缩率差距通常不超过 5%,但 CPU 差距可达 3~4 倍。建议设置为 4~6

gzip_min_length 256 表示只有响应体大于 256 字节才压缩。小于这个大小的响应,压缩后可能反而更大(因为 gzip 有自己的头部开销)。

静态文件浏览器缓存

让浏览器缓存静态资源,可以大幅减少重复请求:

location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2|ttf)$ {
    expires 30d;                     # 浏览器缓存 30 天
    add_header Cache-Control "public, immutable";
    access_log off;                  # 关闭静态文件的访问日志
}

immutable 告诉浏览器这个资源不会改变,不需要重新验证。对于带版本号的静态资源(如 style.abc123.css),这个配置特别有用。

日志优化

高频访问站点的日志写入本身就是一种 IO 开销。除了上面关闭静态资源日志,还可以调整日志缓冲:

access_log /var/log/nginx/access.log main buffer=32k flush=5s;
error_log /var/log/nginx/error.log warn;

buffer=32k 让日志先写入内存缓冲区,每 32k 或每 5 秒才刷一次磁盘,显著降低磁盘写入频率。对于日志量很大的站点,这个优化能减少 80% 以上的磁盘 I/O。

如果你需要临时禁用日志(比如在压测期间),可以设置 access_log off;,但生产环境建议保留日志,只是通过缓冲来优化写入性能。

第五章:压测验证与效果对比

调完参数要验证。推荐两个压测工具:wrkab(Apache Bench)。

使用 wrk 压测

# 安装
sudo apt install wrk

# 4 线程、1000 并发连接、持续 30 秒
wrk -t4 -c1000 -d30s http://your-server/

wrk 的优势是支持 Lua 脚本,可以模拟复杂的请求场景。如果你需要测试 POST 请求或带 Cookie 的场景,wrk 是更好的选择。

使用 ab 压测

# 发起 10000 个请求,并发 500
ab -n 10000 -c 500 http://your-server/

ab 是 Apache 自带的压测工具,简单易用,适合快速验证。但 ab 的并发能力有限,超过 1000 并发时结果可能不准确。

通过压测数据对比,你可以直观看到各项优化的实际效果。

更多更多运维技巧相关内容,可以参考 服务器运维指南 中的系列教程。

更多选购指南相关内容,可以参考 主机选购指南 中的系列教程。

总结清单

把本文的核心配置汇总成一张清单,供你直接对照修改:

  1. worker_processes:设为 auto 或 CPU 核心数
  2. worker_connections:设为 10240+,同时修改系统 ulimit
  3. 事件模型:使用 epoll + multi_accept on
  4. client_body_buffer_size:16k~32k
  5. proxy_buffers:8 个 16k(根据后端响应体大小调整)
  6. fastcgi_buffers:16 个 16k(PHP 站点)
  7. keepalive_timeout:65s
  8. upstream keepalive:32(配合 HTTP/1.1)
  9. Gzip 压缩:level 4,min_length 256
  10. 静态资源:expires 30d + access_log off
  11. 日志缓冲:buffer=32k flush=5s
  12. 压测验证:wrk 或 ab,对比 QPS 和延迟

行动建议:先用 nginx -T 导出当前完整配置,对照上面的清单逐项检查,每改一项就压测一次,记录效果。性能调优不是一次性工程,而是持续观察、持续迭代的过程。

想了解更多服务器运维与优化技巧,欢迎访问 Hostease 中文博客,我们持续分享建站与服务器管理的实用内容。

发表评论