一、为什么要做 Nginx 性能调优
很多个人站长把 Nginx 安装好、配置完虚拟主机之后就再也不管它了。默认配置确实能让网站"跑起来",但离"跑得快"还有不小的差距。尤其是现在的小型服务器,不少站长用的是 1 核 1G 甚至更低的配置,一旦某篇文章被分享出去,并发请求稍微一多,服务器就会 CPU 飙升、响应变慢,甚至出现 502、504 错误,用户一刷新就打不开,体验非常糟糕。
我自己维护过几台不同配置的服务器,踩过不少坑,也总结出一套行之有效的调优流程。这篇文章会把 Nginx 调优的各个关键点完整讲清楚:worker 进程怎么设、连接数怎么算、gzip 怎么开、静态缓存和代理缓存怎么配、超时参数怎么调,最后给出一份可以直接参考的完整配置,并用 ab 压测验证调优效果。内容都是生产环境验证过的经验,不搞玄学。
二、worker 进程与连接数的合理设置
Nginx 采用 master-worker 多进程模型。master 进程负责读取配置、平滑重载和管理 worker,真正处理客户端请求的是 worker 进程。worker_processes 参数控制 worker 进程的数量,最合理的设置是等于 CPU 逻辑核心数。查看核心数可以用:
grep -c processor /proc/cpuinfo
# 或者直接用
nproc对于 1 核的小机器,设置 worker_processes 1 或 2 即可。并不是 worker 越多越好,进程过多反而会增加上下文切换的开销,导致整体性能下降。如果服务器上同时还跑着 MySQL、PHP-FPM、Redis 等其他服务,worker 数量甚至建议比核心数少一点,给其他进程留出 CPU 时间片。
worker_connections 表示每个 worker 进程最多能同时保持的连接数,默认值是 1024,对个人站点来说通常不太够。Nginx 理论上的最大并发连接数约等于 worker_processes 乘以 worker_connections,比如 2 个 worker、每个 4096 连接,理论并发就是 8192。要注意,这个值还会受到系统文件描述符限制的制约,如果 ulimit -n 只有 1024,就算配置文件里写 4096 也达不到,需要同步调整:
# 编辑 /etc/security/limits.conf,加入
* soft nofile 65535
* hard nofile 65535修改后重新登录服务器,或者重启 Nginx 服务,再用 ulimit -n 验证是否生效。
三、事件模型与连接超时优化
events 块中的 use epoll 是 Linux 下最高效的事件驱动模型,适合高并发场景,可以显式写出来。multi_accept on 允许一个 worker 一次性接受多个新连接,也能小幅提升吞吐量。完整的事件配置如下:
events {
use epoll;
worker_connections 4096;
multi_accept on;
}超时参数直接影响用户体验和资源占用。keepalive_timeout 控制客户端长连接的超时时间,默认 75 秒偏长,个人站点设置 30 到 60 秒就够用了;keepalive_requests 默认值是 100,指的是单个长连接上最多处理的请求数,调大到 1000 可以减少重复建连的开销。client_header_timeout 和 client_body_timeout 建议设为 10 到 30 秒,防止慢速客户端长期占用连接。send_timeout 是两次写操作之间的超时,默认 60 秒即可。
keepalive_timeout 60s;
keepalive_requests 1000;
client_header_timeout 10s;
client_body_timeout 30s;
send_timeout 60s;四、开启 gzip 压缩,传输体积立减一大半
HTML、CSS、JavaScript、JSON 这类文本资源压缩率非常高,开启 gzip 后传输体积通常能减少 60% 以上,对带宽有限的小服务器来说收益极为明显。推荐配置如下:
gzip on;
gzip_vary on;
gzip_comp_level 5;
gzip_min_length 1k;
gzip_types text/plain text/css application/json application/javascript application/xml image/svg+xml font/woff2;gzip_comp_level 建议取 5 或 6,压缩率和 CPU 消耗比较均衡,没必要开到 9,收益很小却明显增加 CPU 开销。gzip_min_length 1k 表示小于 1KB 的文件不压缩,因为压缩头部本身也有开销。图片、视频等本身已经压缩过的二进制文件不要放进 gzip_types,压了也白压。
五、静态文件缓存:让浏览器帮你分担压力
个人站点里图片、CSS、JS 往往占了大半流量,给它们配上长时间的浏览器缓存,能显著降低服务器压力、加快二次访问速度。常见的写法是单独一个 location 匹配静态资源:
location ~* \.(jpg|jpeg|png|gif|webp|ico|css|js|woff2)$ {
expires 30d;
add_header Cache-Control "public, max-age=2592000";
access_log off;
}配合 open_file_cache 可以把文件句柄、大小、修改时间缓存在内存里,避免每次请求都做一次磁盘 stat 系统调用,对大量小文件的场景帮助很大:
open_file_cache max=10000 inactive=60s;
open_file_cache_valid 60s;
open_file_cache_min_uses 2;
open_file_cache_errors on;这里要提醒一点:如果站点经常更新 CSS 和 JS,建议在文件引用路径上加上版本号或者内容哈希,避免浏览器缓存了旧文件导致样式错乱。
六、反向代理缓存,减轻后端 PHP 的压力
如果网站是 Nginx 加 PHP-FPM 的经典架构,每次请求都要走一遍 PHP 解析。对于内容基本不变的页面,可以在 Nginx 这一层做代理缓存,命中缓存的请求完全不需要再动 PHP,速度可以从几百毫秒降到几毫秒。核心配置如下:
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=site_cache:10m max_size=1g inactive=60m use_temp_path=off;
server {
...
location / {
proxy_cache site_cache;
proxy_cache_key $scheme$request_method$host$request_uri;
proxy_cache_valid 200 301 302 10m;
proxy_cache_bypass $cookie_nocache $arg_nocache;
proxy_pass http://127.0.0.1:8080;
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_cache_bypass 配合 Cookie 判断,可以让登录用户绕过缓存,避免出现登录状态错乱的怪问题。keys_zone 的 10m 大约能存放 8 万个缓存 key,个人站点绰绰有余。修改配置后记得 nginx -t 检查语法,再 nginx -s reload 平滑重载,不会中断现有连接。
七、HTTPS 与 HTTP/2 配置
现在的搜索引擎和浏览器都已经把 HTTPS 当成标配,还在用纯 HTTP 的站点会被标记为不安全,排名和访问转化都会受影响。个人站长申请证书最简单的方式是用 Let's Encrypt 的 certbot 工具,一条命令就能自动申请并配置好证书,到期前还能自动续期,完全免费。配置 HTTPS 时几个关键参数值得注意:ssl_protocols 建议只启用 TLSv1.2 和 TLSv1.3,旧版本的 TLS 协议存在已知漏洞,不要再开启;ssl_session_cache 开启会话缓存,可以显著减少 TLS 握手的开销;开启 OCSP Stapling 能加快证书链验证的速度,让首次访问连接更快。
listen 443 ssl http2;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;配合 HTTPS 使用 HTTP/2 几乎是零成本的性能提升。HTTP/2 支持多路复用,多个请求可以共用一条连接并发传输,不再像 HTTP/1.1 那样受队头阻塞问题的困扰,页面加载速度的提升非常明显,尤其是图片、脚本资源较多的站点。开启 HTTP/2 之后,记得把页面里的内嵌资源统一改成同域相对路径,避免因为混用不同协议产生额外的重定向请求。证书续期后需要重载 Nginx 让新证书生效,可以在 crontab 里加一条定时任务:certbot renew --quiet --deploy-hook "nginx -s reload",这样整个 HTTPS 生命周期就全自动了。
八、日志与基础安全设置
访问日志写得太频繁也会消耗磁盘 IO。静态资源的 access_log 已经关了,其他请求可以保留日志但精简格式,把响应时间也记进去,方便排查慢请求:
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" $request_time $upstream_response_time';
access_log /var/log/nginx/access.log main;再补几个基础安全项:server_tokens off 隐藏 Nginx 版本号;客户端请求体大小按需限制,防止有人上传超大文件拖垮磁盘;给管理后台目录加上访问控制,可以用 allow 和 deny 只放行自己的 IP。
server_tokens off;
client_max_body_size 20m;九、一份可直接参考的完整配置
把上面这些要点整合起来,就是一份适合个人站点生产环境使用的完整配置,按自己的域名和端口修改即可:
user www-data;
worker_processes 2;
pid /run/nginx.pid;
events {
use epoll;
worker_connections 4096;
multi_accept on;
}
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
server_tokens off;
keepalive_timeout 60s;
keepalive_requests 1000;
client_max_body_size 20m;
gzip on;
gzip_vary on;
gzip_comp_level 5;
gzip_min_length 1k;
gzip_types text/plain text/css application/json application/javascript application/xml image/svg+xml font/woff2;
open_file_cache max=10000 inactive=60s;
open_file_cache_valid 60s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" $request_time $upstream_response_time';
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=site_cache:10m max_size=1g inactive=60m use_temp_path=off;
server {
listen 80;
server_name www.example.com;
access_log /var/log/nginx/access.log main;
location / {
proxy_cache site_cache;
proxy_cache_key $scheme$request_method$host$request_uri;
proxy_cache_valid 200 301 302 10m;
proxy_cache_bypass $cookie_nocache $arg_nocache;
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location ~* \.(jpg|jpeg|png|gif|webp|ico|css|js|woff2)$ {
expires 30d;
add_header Cache-Control "public, max-age=2592000";
access_log off;
}
}
}十、用 ab 压测验证调优效果
调优有没有效果,不能靠感觉,要用数据说话。Apache 自带的 ab 工具就可以做简单的压测,先测调优前,再测调优后,对比结果。示例:
ab -n 2000 -c 100 https://www.example.com/重点关注三个指标:Requests per second 每秒请求数、Time per request 平均响应时间、Failed requests 失败请求数。我自己测试的结果是,开启 gzip 和代理缓存之后,同一个页面的每秒请求数提升了好几倍,平均响应时间从几百毫秒降到几十毫秒,效果立竿见影。压测时注意控制并发数,不要把自己的服务器压垮了。
十一、总结与常见误区
最后把个人站长最容易犯的几个错误总结一下。第一,worker_processes 不是越大越好,超过 CPU 核心数反而有害;第二,gzip 级别没必要开到 9,5 和 6 已经足够;第三,开了代理缓存一定要处理登录态问题,否则会出现张冠李戴的缓存错乱;第四,改完配置务必 nginx -t 检查,再平滑重载,避免语法错误导致服务中断;第五,静态资源缓存要配合版本号使用,否则更新了文件用户看到的还是旧的。
调优是一个持续迭代的过程,没有一劳永逸的万能配置。建议先用压测工具建立基线,再一项一项调整、对比、记录,找到最适合自己站点和服务器配置的组合。希望这篇实战笔记能帮助你把服务器调得更快、更稳、更省心。