Nginx 调优不靠堆配置:从连接数到缓存,我把踩过的坑都列出来了
站点平时跑得好好的,一到大促或者被爬虫扫一轮就开始零星冒 502,登录服务器看 CPU 和内存都不高,Nginx 的 error log 里翻来覆去就是 connect() failed 和 worker_connections are not enough。这种场景我见得太多了,第一反应往往是把 worker_connections 往上加,加完发现没什么用,问题照旧。
调优这件事,方向比数值重要。下面按连接层、缓存层、静态资源层分开说,每一层我都把真正卡人的地方挑出来讲。
连接数不是越大越好,句柄先撑不住
worker_connections 这个参数最容易被误用。它限制的是单个 worker 进程能同时处理的连接数,但一个客户端连接通常要占两个位置——前端一个,和后端 upstream 通信又一个。所以理论并发大约是 worker_processes × worker_connections ÷ 2。
问题在于很多人只改这一项,忘了系统层面的文件句柄限制。Linux 默认的 nofile 通常是 1024,Nginx 跑到这个数就再也拿不到新句柄了,日志里报的正是那句 worker_connections are not enough。
正确的做法是两处一起改。Nginx 主配置里加一行 worker_rlimit_nofile 65535,同时把系统的 limits.conf 和 systemd 的 LimitNOFILE 都放开。我一般会让 Nginx 的 worker_rlimit_nofile 略小于系统上限,留一点余量给日志和监控进程。
改完记得 reload 之后用 ss -s 看实际连接数,别只看配置写得多漂亮。
keepalive 两头都要配,只改一头等于白干
keepalive_timeout 默认 75 秒,对现在的移动端和 API 场景偏长了。长连接占着 worker 的资源不放,短连接又频繁握手,两头都不讨好。
我的习惯是前端设 65 秒,和大多数 CDN 的回源超时对齐。这样 CDN 那边还没断,Nginx 这边先释放,不会出现回源时连接已失效的情况。
后端 upstream 块里也要配 keepalive。这里有个坑:upstream 的 keepalive 只对 HTTP/1.1 生效,你必须在 proxy_set_header Connection "" 里把 Connection 头清空,否则 Nginx 会老老实实按 HTTP/1.0 的短连接去连后端。少了这一行,配了跟没配一样。
如果后端是 PHP-FPM,那走的是 FastCGI,得用 fastcgi_keep_conn on。这点很多人搞混,以为 upstream 的配置对所有后端都管用。
gzip 和缓存:省的是带宽,花的是 CPU,得算账
gzip 开不开,取决于你的内容构成。HTML、CSS、JS 这类文本压完能省六七成流量,值得开。但图片、视频、woff2 字体本身已经是压缩格式,再压一遍基本没效果,纯浪费 CPU。
更反直觉的是小文件。1KB 以下的响应压完可能还变大,因为要加 gzip 头。我一般会设 gzip_min_length 1024,低于这个数的直接跳过。
静态资源这块,open_file_cache 是性价比很高的一项。它把文件描述符和元信息缓存在内存里,命中之后不用每次都去 stat 磁盘。对于那种每天被读几百万次的小图标、logo,效果很明显。
配的时候注意 inactive 和 max 两个值。inactive 是多久没访问就踢出缓存,max 是缓存条目上限。我一般 inactive 设 20s,max 设 10000,具体看你的文件数量。
还有个容易忽略的点:sendfile on 和 tcp_nopush on 要一起开。sendfile 让数据直接从内核发到网卡,绕开用户态拷贝;tcp_nopush 则保证数据包填满了再发,减少小包数量。两个配合,静态文件传输效率能上一个台阶。
落到硬件上,瓶颈往往不在 Nginx
配置调到极限,单机也就那样了。Nginx 本身很轻,真正吃资源的是后端应用和数据库。当单台机器扛不住的时候,与其继续抠参数,不如把静态资源分出去。
我一般的做法是把图片、附件这类东西放到独立的大带宽服务器上,让 Nginx 只做反向代理和动态请求转发。秀米云的美国硅谷大带宽服务器 XV 配的是 E5-2620*2 和 32G 内存,G 口带宽,月付 $493.50,适合静态资源量大的站点做分流。如果预算没那么高,台湾服务器2 是 E5-2630L / 16G / 20M,月付 $119.00,面向亚太用户延迟也还过得去。
换到独立机器之后,Nginx 的配置可以简化很多,不用再为了一点点并发去死抠参数。
收尾:先定位再调参
调 Nginx 之前,先看清楚卡在哪一层。连接数不够就去查句柄和 worker 配置,响应慢就去查后端和缓存命中率,带宽跑满才考虑加机器或者上 CDN。
我的判断标准很简单:如果 CPU 没满、内存没满、磁盘 IO 不高,那问题多半不在 Nginx 本身,而在它背后的东西。这时候改配置是治标,换架构才是治本。
先按上面三层对一遍,再决定是加参数还是加机器。