Nginx 调优到底改哪几个参数?从 worker 到 keepalive 的实操拆解
一台 2 核 4G 的机器,Nginx 默认配置跑静态站,日 PV 几千没问题。但流量一上来,连接数爬到三四千就开始出现 502 和超时,CPU 看着没满,带宽也没跑满。这种情况我见得太多了,问题不在硬件,在几个关键参数压根没动过。
Nginx 的默认值是为通用场景设计的,偏保守。它假设你的机器可能只有 1 核,可能内存很小,所以 worker_connections 默认 512,worker_processes 默认 1。放到一台 4 核 8G 的机器上,这个配置等于让三个核在旁边看着。
下面按影响面从大到小说几个我每次上线都会调的参数。不是让你照抄,是让你知道每个值改了之后会发生什么。
worker_processes 和 worker_connections 怎么配才不浪费核
worker_processes 设成 auto,Nginx 会自动读 CPU 核数。4 核就是 4 个 worker,每个 worker 独立处理连接,不用加锁。这个基本没有争议,除非你的机器上还跑着别的吃 CPU 的服务,那手动设成核数减一也行。
真正容易配错的是 worker_connections。它限制的是单个 worker 能同时处理的最大连接数,不是整个 Nginx 的连接上限。整机上限大致是 worker_processes 乘以 worker_connections。4 个 worker 每个 1024,理论并发连接就是 4096。
但这里有个坑:一个浏览器打开一个页面,可能同时发起 6 到 8 个 TCP 连接去拉 CSS、JS、图片。所以 4096 个连接对应的实际访客数可能只有几百人同时在线。按我的经验,静态资源站按「预期同时在线人数乘以 8」来估算 worker_connections 比较稳。
连接数上去之后,系统层面的文件描述符限制也得跟着放开。worker_connections 设了 8192,但系统 ulimit 还是 1024,多出来的连接会被内核直接拒掉,日志里看到的是「too many open files」。这个报错我碰到过好几次,每次都是忘了改 limits.conf。
sendfile 和 tcp_nopush 组合起来省的是什么
Nginx 处理静态文件时,默认走的是「读文件到用户态缓冲区,再写到 socket」的路径。多了一次内存拷贝。sendfile on 让内核直接把文件数据从磁盘缓冲区送到网卡,不走用户态。对图片、CSS、JS 这类静态资源,省下的 CPU 时间很可观。
tcp_nopush 要和 sendfile 一起用。它的作用是把多个小包攒成一个大的 TCP 段再发出去,减少网络上的小包数量。开了之后,一个页面里的十几个静态请求,响应头可能合并在一两个包里发回来。
这两个参数只对静态文件生效,反向代理转发的动态请求不受影响。如果你的站主要是 API 转发,改这两个参数不会有明显变化。
还有一个 tcp_nodelay,通常和 tcp_nopush 配合用。tcp_nopush 攒包,tcp_nodelay 确保最后一个包立刻发出去不等待。两个都开,既减少小包又不增加延迟。
keepalive_timeout 设长了占内存,设短了握手多
keepalive_timeout 控制的是连接空闲多久之后关闭。默认 75 秒,意思是客户端拉完页面后,TCP 连接还保持 75 秒,期间如果客户端再发请求,直接复用这个连接,不用重新三次握手。
设长了,服务端要维持大量空闲连接,每个连接占一点内存。设短了,客户端频繁重连,握手开销和 TIME_WAIT 状态堆积都会增加。75 秒对多数站点是合理的。但如果是 API 服务,客户端是程序而不是浏览器,连接复用频率高,可以设到 120 秒甚至更长。
我一般会同时调 keepalive_requests,默认 100,意思是单个连接最多处理 100 个请求后强制关闭。这个值设大一点,比如 1000,能减少连接重建次数。但设太大也不行,长连接占用 worker 的处理时间,极端情况下可能影响新连接的接入。
上游连接也有对应的 keepalive 配置。如果你用 Nginx 做反向代理,upstream 块里的 keepalive 设成 32 或 64,能让 Nginx 和后端服务之间也复用连接,省掉大量 TIME_WAIT。
带宽和硬件才是最终天花板
参数调得再好,机器本身的出口带宽和磁盘 IO 决定了上限。一台 100M 带宽的机器,理论峰值下载速度大概 12.5MB/s。一个页面 500KB,理想情况下同时只能服务 25 个首次访问的用户。超过这个数,要么排队要么丢包。
如果跑的是动态站或者 API,CPU 和内存的瓶颈会比带宽来得更早。Nginx 本身很省资源,但后端如果跑着 PHP 或 Java,那才是吃资源的大头。
需要大带宽跑静态资源或者做 CDN 回源的,可以看看香港自营物理服务器(100M),E3-1230 V2 配 16G 内存,100M 带宽,月付 ¥3450。这个配置跑 Nginx 静态站,worker_connections 设 4096 完全撑得住。
最后说一句:改完参数记得用 nginx -t 检查语法,再 reload。别直接 restart,线上服务会有几百毫秒的中断。压测工具用 ab 或者 wrk 先跑一轮,看 QPS 和延迟变化,比凭感觉改要靠谱得多。