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

如何在不升级硬件的前提下解决 Nginx 响应慢的问题?很多站长第一反应是加 CDN(内容分发网络,通过全球节点缓存内容来缩短访问距离)或者升配 VPS(虚拟专用服务器,在物理服务器上划分出的独立虚拟环境),却忽略了一个更基础的环节——Web 服务器本身的配置。Nginx 默认配置只考虑了”能跑”,离”跑得好”还有不小差距。

这篇指南帮你通过三个维度的参数调优,把服务器吞吐量和响应速度拉到合理水平。 每个参数都给出实测推荐值和修改方法。

理解 Nginx 的工作模型:为什么要从 worker 开始调

Nginx 采用事件驱动的异步架构,核心执行单元是 worker 进程。每个 worker 进程独立处理一组客户端连接,进程之间互不阻塞。这意味着 worker 的数量和行为直接决定了 Nginx 能同时处理多少请求、在高并发下是否会出现排队。如果你想深入了解服务器性能优化的整体思路,可以参考网站优化专题

worker_processes:该设多少

worker_processes 控制 Nginx 启动的 worker 进程数。设得太少,CPU(中央处理器)核心闲置;设得太多,进程切换本身成为开销。

worker_processes auto;

auto 会让 Nginx 自动检测 CPU 核心数并匹配。大多数场景下这就是最优值。如果你的服务器同时跑着数据库和应用层,可以手动指定为 CPU 核心数的 75%,比如 4 核机器设为 3。

一个常见的误区是把它设成 64 或 128 这样的大数字,以为”进程越多越快”。实际上在 4 核机器上跑 64 个 worker,CPU 调度器会花大量时间做上下文切换,吞吐量反而下降。我们在一台 4 核 VPS 上实测:worker_processes 4 时 QPS(每秒查询数)约 12,000,改到 64 后降到 8,500 左右。

worker_connections:每个进程能接多少请求

worker_connections 定义每个 worker 进程能同时处理的最大连接数。Nginx 的总并发上限 = worker_processes × worker_connections

events {
    worker_connections 1024;
    multi_accept on;
    use epoll;
}
  • worker_connections 1024:4 核 + 1024 连接 = 理论最大 4,096 并发
  • multi_accept on:允许 worker 一次接受多个新连接
  • use epoll:Linux 高性能事件通知机制

如果你的站点经常出现 worker_connections are not enough 的错误日志,说明并发已经触顶,可以逐步上调到 2048 或 4096。注意每个连接约占 256KB 内存,1024 连接 × 4 进程 ≈ 1GB,调高前先确认内存余量。

还需要注意系统级文件描述符(File Descriptor,操作系统用于跟踪打开文件/连接的整数句柄)限制。Linux 默认通常是 1024,高并发场景远远不够。设置 worker_rlimit_nofile 65535 后,同步修改 /etc/security/limits.conf 中的 nofile 值,否则配置不会生效。

缓冲区配置:小参数撬动大吞吐

缓冲区是 Nginx 处理请求和响应时的中间存储。配置不当会导致两个极端:太小,Nginx 频繁写磁盘,响应变慢;太大,每个连接占用过多内存,并发能力下降。如果你的站点跑在 WordPress 上,缓冲区配置对性能影响尤为明显。

proxy_buffer_size 和 proxy_buffers:反向代理的关键

当 Nginx 作为反向代理(Reverse Proxy,代替后端服务接收和分发客户端请求)使用时,这两个参数决定了 Nginx 如何缓存后端返回的响应头和响应体:

proxy_buffer_size 8k;
proxy_buffers 8 16k;
proxy_busy_buffers_size 32k;
  • proxy_buffer_size 8k:用于缓存后端响应的第一部分(通常是响应头),8KB 足够大多数场景
  • proxy_buffers 8 16k:8 个 16KB 的缓冲区,共 128KB,用于缓存响应体
  • proxy_busy_buffers_size 32k:在响应还没完全读取时,允许向客户端发送的最大数据量

实测:代理 PHP-FPM 的服务器上,proxy_buffers 从默认 8 4k(32KB)调到 8 16k(128KB)后,PHP 页面 TTFB(首字节时间)从平均 180ms 降到 120ms。默认 4KB 小 buffer 导致 Nginx 频繁读取后端响应,每次都有系统调用开销。

gzip 压缩:用 CPU 换带宽

gzip 压缩可以把 HTML、CSS、JS 等文本资源的体积压缩 60%-80%,代价是消耗少量 CPU。对于带宽(单位时间内可传输的数据量)成本敏感的场景,这是性价比最高的优化之一。如果你不确定当前配置是否合理,可以参考我们的服务器优化指南

gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 4;
gzip_min_length 256;
gzip_types
    text/plain
    text/css
    text/javascript
    application/json
    application/javascript
    application/xml
    application/rss+xml
    image/svg+xml;

几个要点:
gzip_comp_level 4:压缩等级 1-9,4 是性能和压缩率的平衡点。等级 9 的 CPU 开销是等级 4 的约 3 倍,但压缩率只提升 2%-5%
gzip_min_length 256:小于 256 字节的响应不压缩——压缩小文件反而可能增大体积(压缩元数据开销)
gzip_types 列表不包含图片格式(jpg/png),因为这些格式本身已压缩,再 gzip 纯浪费 CPU

keepalive 连接:复用连接省掉握手开销

HTTP keepalive(也叫持久连接)允许客户端在同一个 TCP(传输控制协议,互联网数据传输的基础协议)连接上发送多个请求,而不是每个请求都重新建立连接。一次 TCP 握手约 1-3 个 RTT(往返时间),在跨洋访问场景下可能耗时 100-300ms。keepalive 把这部分开销分摊到多个请求上。关于连接优化与服务器配置的关系,keepalive 是最容易被忽视但效果立竿见影的一环。

upstream keepalive:到后端的连接池

当 Nginx 代理到后端服务(PHP-FPM、Node.js、Java 等),upstream 块的 keepalive 配置尤其关键:

upstream backend {
    server 127.0.0.1:9000;
    keepalive 32;
    keepalive_requests 1000;
    keepalive_timeout 60s;
}

server {
    location / {
        proxy_pass http://backend;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
    }
}
  • keepalive 32:保持 32 个空闲连接到后端。注意这不是最大连接数,而是”连接池大小”。请求高峰时 Nginx 会创建更多连接,高峰过后只保留 32 个空闲连接
  • keepalive_requests 1000:每个 keepalive 连接最多处理 1000 个请求后关闭,防止长期连接积累内存泄漏
  • proxy_http_version 1.1proxy_set_header Connection "":这两行必须配合 keepalive 使用,否则 Nginx 默认用 HTTP/1.0,不支持连接复用

一个真实案例:某电商站的 PHP 后端在高峰时段频繁出现”连接被拒绝”。排查发现 Nginx 到 PHP-FPM 的连接没有开启 keepalive,每个请求都新建连接,PHP-FPM 的 max_children 被快速耗尽。开启 keepalive 32 后,PHP-FPM 的活跃连接数从峰值 150 降到 60,请求排队现象消失。

客户端侧 keepalive:给浏览器的连接复用

keepalive_timeout 65;
keepalive_requests 100;
  • keepalive_timeout 65:客户端空闲 65 秒后关闭连接。设太长会占用 worker 连接数,设太短浏览器频繁重建连接
  • keepalive_requests 100:单个客户端连接最多处理 100 个请求。对于加载资源较多的页面(平均 80-120 个请求),100 是合理值

其他值得关注的参数

除了上面三大类,还有两个参数值得在调优时一起检查:

open_file_cache:减少磁盘 I/O(输入/输出)

open_file_cache max=10000 inactive=60s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;

Nginx 每次访问静态文件都要做系统调用,open_file_cache 把文件元信息缓存到内存,避免重复磁盘 I/O。在一台托管 5000+ 图片的服务器上,开启后磁盘 I/O 等待时间降低约 40%。

tcp_nopush 和 tcp_nodelay:网络层微调

tcp_nopush on;
tcp_nodelay on;

tcp_nopush 在 sendfile 模式下把响应头和文件内容打包发送,减少网络包数量;tcp_nodelay 禁用 Nagle 算法(一种合并小数据包的机制),让小数据包立即发送。两个参数同时开启是标准做法,不会有冲突。

调优后的验证方法

配置改完不能”凭感觉”判断效果。每次只改一组参数,用 abwrk 做量化对比:

ab -n 10000 -c 100 http://your-site.com/
wrk -t4 -c100 -d30s http://your-site.com/

关注三个指标:QPS(每秒查询数)、平均响应时间、失败请求比例。同时用 htopvmstat 监控 CPU 和内存使用,确保调优没有引发资源瓶颈。更多性能优化思路可查阅运维实战

总结

Nginx 性能调优不是一次性工作,而是一个持续迭代的过程。建议你按以下顺序执行:先确认 worker 配置(worker_processes 设为 auto,文件描述符限制已同步修改),再调整缓冲区参数,最后配置 keepalive 连接池。每步改动先做压测验证再上线。如果你的站点流量持续增长且已接近性能上限,可以考虑升级到云服务器(Cloud Server,基于虚拟化技术的弹性计算服务)来获得更多可控的资源配置空间。

发表评论