Nginx 性能调优完全指南:让你的网站飞起来

Nginx 性能调优完全指南:让你的网站飞起来

作为一个草根站长,网站访问速度直接决定了用户体验和搜索引擎排名。Nginx 作为目前最流行的 Web 服务器,默认配置其实只发挥了它 60% 左右的性能。本文把我自己在多个站点上实践过的 Nginx 调优经验完整分享出来,从最基础的配置到高级优化手段,一步一步带你调优,实测下来响应时间至少能缩短 30% 到 50%。

一、基准测试:先摸清家底再动手

调优之前一定要先做基准测试,这是很多人忽视的一步。没有基准数据,你根本不知道优化措施到底有没有效果,也不知道瓶颈在哪里。我推荐使用 ab(Apache Bench)工具做测试:

# 安装 ab
apt install -y apache2-utils

# 并发 100,总共发送 1000 个请求
ab -n 1000 -c 100 https://你的域名/

# 更接近真实用户场景的测试(持续 10 秒的压力测试)
ab -t 10 -c 50 https://你的域名/

测试结果中重点关注以下几个指标。第一个是 Requests per second(每秒请求数),这个数字越大说明服务器的并发处理能力越强。第二个是 Time per request(平均每个请求的响应时间),这个数字越小用户体验越好。第三个是 Failed requests,任何失败请求都要排查原因。最后还有一个 Transfer rate(传输速率),这个反映了服务器的带宽利用情况。

测试完成后用文本保存结果,等调优完成后再测一次做对比。我的习惯是写一个简单的 Shell 脚本,一键执行基准测试并把结果追加到日志文件里:

#!/bin/bash
LOG=/var/log/nginx/benchmark.log
echo "=== $(date) ===" >> $LOG
ab -n 1000 -c 100 https://你的域名/ >> $LOG 2>&1
echo "" >> $LOG

这样每次调优前后的数据都有记录,优化效果一目了然。

二、Worker 进程配置:最基础也最有效

Nginx 采用多进程模型,有一个 master 进程和多个 worker 进程。worker 进程的数量和配置直接影响并发处理能力。打开 /etc/nginx/nginx.conf,修改以下核心参数:

# 设置为 auto,Nginx 自动检测 CPU 核心数来决定 worker 进程数量
worker_processes auto;

# 每个 worker 的最大连接数
events {
    worker_connections 10240;
    use epoll;
    multi_accept on;
}

这几个参数需要重点理解一下。worker_processes auto 的意思是 Nginx 会按照 CPU 核心数启动对应数量的 worker 进程。比如一台 4 核的服务器就启动 4 个 worker 进程。这个数值不要超过 CPU 核心数,因为进程数超过核心数反而会因为上下文切换而降低性能,不如不设。

worker_connections 10240 表示每个 worker 进程最多能同时处理 10240 个连接。那么整台服务器的最大并发连接数就是 worker_processes × worker_connections。4 核 × 10240 = 40960 个并发连接,对于个人站长的中小型网站来说完全够用了。如果你的服务器是 2 核的,可以适当降低这个值,比如设到 5120,避免内存过度消耗。

use epoll 是 Linux 下最高效的 I/O 事件处理模型。Nginx 会自动检测并启用它,但显式写出来更保险一些。最后 multi_accept on 允许一个 worker 进程在接受新连接时一次性接受所有等待中的连接,而不是逐个接受,这样可以提高连接接受效率。

三、启用 Gzip 压缩:性价比最高的优化

Gzip 压缩绝对是性价比最高的优化手段,几乎不需要任何成本就能减少 60% 到 70% 的传输体积。在 http 块中添加以下配置:

http {
    gzip on;
    gzip_min_length 1k;
    gzip_comp_level 6;
    gzip_types text/plain text/css text/javascript application/javascript application/json application/xml image/svg+xml;
    gzip_vary on;
    gzip_disable "msie6";
    gzip_proxied any;
}

几个关键参数需要根据实际情况调整。gzip_comp_level 的取值范围是 1 到 9,压缩级别越高压缩率越大但 CPU 消耗也越高。我实测过不同级别的效果:级别 2 压缩率约 40%,级别 6 约 55%,级别 9 约 57%。从 6 到 9 只提升了 2% 的压缩率,但 CPU 消耗翻了一倍。所以 6 是最佳的平衡点。

gzip_min_length 1k 的意思是文件小于 1KB 时不压缩。因为小文件压缩后反而可能变大(压缩头本身也有开销),得不偿失。gzip_types 只配置文本类型的文件就够了,图片、视频等二进制文件本身已经压缩过了,再压缩没有意义甚至可能变慢。

配置好之后,可以用 curl -H "Accept-Encoding: gzip" -I https://你的域名/css/style.css 查看响应头中是否包含 Content-Encoding: gzip,如果有就说明配置生效了。

四、静态文件缓存设置

对于 CSS、JS、图片等不经常变化的文件,让浏览器缓存起来可以大幅减少重复请求,对二次访问的速度提升非常明显:

location ~* \.(jpg|jpeg|png|gif|ico|css|js|webp|woff2?|ttf|svg)$ {
    expires 30d;
    add_header Cache-Control "public, immutable";
    access_log off;
    log_not_found off;
}

这个配置的作用是告诉浏览器:这些文件可以缓存 30 天(expires 30d)。immutable 这个指令比较新,它告诉浏览器就算用户手动刷新页面,也不需要请求服务器验证文件是否过期,直接用缓存就行。access_log off 的意思是这些静态文件的请求不写入访问日志,可以节省磁盘 I/O 和日志文件的大小。log_not_found off 则是不记录文件不存在的 404 错误,避免大量爬虫请求不存在的图标文件时把日志撑爆。

五、开启 HTTP/2 提升加载性能

HTTP/2 协议相比 HTTP/1.1 有多个重要改进:多路复用允许在一个连接上同时传输多个请求和响应,解决了 HTTP/1.1 的队头阻塞问题;头部压缩大幅减少了请求头的大小;服务器推送允许服务器主动将资源推送给客户端。这些特性对页面加载速度的提升非常明显。

开启 HTTP/2 的前提是已经配置了 HTTPS:

server {
    listen 443 ssl http2;
    
    # HTTP 自动跳转到 HTTPS
    listen 80;
    if ($scheme = http) {
        return 301 https://$host$request_uri;
    }

    ssl_certificate /etc/nginx/ssl/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/privkey.pem;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;
}

配置 HTTPS 必不可少的当然是 SSL 证书。推荐使用 acme.sh 配合 Let's Encrypt 自动申请和续签免费证书。配置好之后在 listen 行加上 http2 参数即可。注意 ssl_session_cache shared:SSL:10m 这个配置,它设置了 SSL 会话缓存的共享内存大小为 10MB。大约可以缓存 40000 个 SSL 会话,对于大多数站点来说完全够用。启用会话缓存后,客户端在第一次 SSL 握手后可以复用缓存的会话参数,后续连接只需要一次往返就能完成握手,显著减少了 HTTPS 的延迟开销。

六、FastCGI 缓存:让动态页面变静态

对于 PHP 动态站点,FastCGI 缓存是一项被很多人忽视但效果极其显著的技术。它把 PHP 生成的页面缓存到 Nginx 层,后续相同的请求直接从缓存返回,不再执行 PHP 脚本,响应速度可以提升 10 倍以上:

# 在 http 块中定义缓存路径和参数
http {
    fastcgi_cache_path /tmp/nginx_fastcgi_cache levels=1:2 keys_zone=fcgicache:100m inactive=60m;
    fastcgi_cache_key "$scheme$request_method$host$request_uri";
}

# 在 server 块中启用缓存
server {
    set $skip_cache 0;

    # 登录用户和评论提交不缓存(否则管理员看不到更新)
    if ($http_cookie ~* "comment_author|wordpress_logged|typecho_auth") {
        set $skip_cache 1;
    }

    # 后台页面不缓存
    if ($request_uri ~* "/admin/|/login") {
        set $skip_cache 1;
    }

    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;

        fastcgi_cache fcgicache;
        fastcgi_cache_valid 200 60m;
        fastcgi_cache_bypass $skip_cache;
        fastcgi_no_cache $skip_cache;
        fastcgi_cache_use_stale error timeout invalid_header updating http_500;
        add_header X-FastCGI-Cache $upstream_cache_status;
    }
}

这个配置中,fastcgi_cache_path 的参数含义是:cache 文件存放在 /tmp/nginx_fastcgi_cache 目录,levels=1:2 表示目录层级结构,keys_zone=fcgicache:100m 表示分配 100MB 共享内存用于缓存键,inactive=60m 表示 60 分钟内没有被访问的缓存会被清理。

最后一行 add_header X-FastCGI-Cache $upstream_cache_status 非常有用,它会在响应头中增加一个 X-FastCGI-Cache 字段,值为 HIT 表示命中缓存,MISS 表示未命中,BYPASS 表示跳过缓存。用浏览器开发者工具就能看到,方便你调试缓存是否正常工作。

七、内核参数调优

Nginx 跑得再快,如果 Linux 内核限制了连接数也是白搭。以下是我在 Debian/Ubuntu 系统上常用的内核优化参数,加到 /etc/sysctl.conf 末尾:

# 最大文件打开数,Nginx 每个连接对应一个文件描述符
fs.file-max = 1000000

# 启用 TIME_WAIT 套接字重用
net.ipv4.tcp_tw_reuse = 1
# 缩短 FIN-WAIT-2 超时时间
net.ipv4.tcp_fin_timeout = 15

# TCP 连接队列大小
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535

# 本地端口范围
net.ipv4.ip_local_port_range = 1024 65000

# TCP 读写缓冲区
net.core.rmem_default = 65536
net.core.wmem_default = 65536
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216

# 生效
sysctl -p

同时修改 /etc/security/limits.conf,增加 Nginx 用户的文件打开数限制:

* soft nofile 1000000
* hard nofile 1000000
root soft nofile 1000000
root hard nofile 1000000

修改完后需要重新登录或者重启 Nginx 服务才会生效。

八、监控与持续优化

调优不是一次性工作,需要持续监控和调整。我每天登录服务器都会看一下这几个指标:

# 查看 Nginx 活动连接状态
curl http://127.0.0.1/nginx_status

# 查看系统 TCP 连接状态统计
ss -s

# 实时查看请求日志中的响应时间
tail -f /var/log/nginx/access.log | awk '{print $NF}'

要精确记录每个请求的处理时间,可以在 Nginx 配置中添加自定义日志格式:

log_format timed '$remote_addr - $remote_user [$time_local] '
                 '"$request" $status $body_bytes_sent '
                 '"$http_referer" "$http_user_agent" '
                 'rt=$request_time uct=$upstream_connect_time '
                 'uht=$upstream_header_time urt=$upstream_response_time';

access_log /var/log/nginx/access.log timed;

这样每条日志都会记录请求总时间($request_time)和后端响应时间($upstream_response_time)。如果发现某个页面请求时间超过 2 秒,就需要排查是 PHP 执行慢还是数据库查询慢,还是 Nginx 本身配置有问题。

九、总结

Nginx 调优不是一蹴而就的事,建议按照本文的顺序逐步调整,每次只改一个参数,然后跑一次基准测试对比结果。我个人经验中最立竿见影的三个优化是:Gzip 压缩、HTTP/2 协议和 FastCGI 缓存。做好这三项,你的网站响应时间基本能减少一半。

最后提醒一个原则:不要在没做基准测试的情况下盲目套用别人的配置。每台服务器的硬件配置、运行的网站类型、用户的访问模式都不一样,适合别人的配置不一定适合你。先测再改,用数据说话,这是运维工作最基本也是最重要的原则。

Last modification:July 27th, 2026 at 08:16 am

Leave a Comment