高流量网站的Nginx性能调优必备清单
一份实用的Nginx性能清单,涵盖工作进程、连接、缓冲区、缓存、压缩、日志、超时、TLS和静态文件。
高流量网站的Nginx性能调优必备清单
将Nginx性能调优视为一份清单,而不是一场猜谜游戏,这样会更容易。从决定Nginx能接受多少流量的限制开始,然后向外扩展到缓冲、缓存、压缩、日志记录、超时、TLS以及其背后的后端服务。
不要一次性将所有指令都投入生产环境。一份好的Nginx性能调优清单能帮助你决定检查什么、为什么重要,以及过度调整可能出什么问题。对于一个以静态内容为主的文档网站来说,正确的设置并不适用于长轮询API或文件上传服务。
1. 优化工作进程和连接
Nginx采用主-从进程模型。主进程读取配置并管理工作进程,而工作进程则处理实际的客户端请求。正确配置这些可以显著提高并发性和资源利用率。
worker_processes
该指令决定Nginx将生成多少个工作进程。通常,将其设置为auto可以让Nginx检测CPU核心数并生成相等数量的工作进程,这是一种常见的做法。
worker_connections
定义单个工作进程可以打开的最大并发连接数。此设置与worker_processes共同决定了Nginx理论上可以处理的总并发连接数(worker_processes * worker_connections)。
multi_accept
允许一个工作进程一次接受多个新连接,从而防止在高负载下出现潜在瓶颈。
# /etc/nginx/nginx.conf
worker_processes auto; # 通常设置为 'auto' 或 CPU 核心数
events {
worker_connections 1024; # 根据服务器容量和预期负载调整
multi_accept on;
}
提示: 如果CPU持续偏高,单独提高
worker_connections并不能解决问题。首先确认CPU消耗是否来自TLS握手、压缩、日志记录、正则表达式密集型路由或上游应用程序。
2. 高效的连接管理
优化Nginx处理网络连接的方式可以减少开销并提高响应能力。
keepalive_timeout
指定一个保持活动的客户端连接将保持打开多长时间。重用连接可以减少建立新TCP连接和SSL握手的开销。根据应用程序的交互性,常见值为15-65秒。
sendfile
启用文件描述符之间的直接数据传输,绕过用户空间缓冲。这在提供静态文件时能显著提高性能。
tcp_nopush
与sendfile配合使用。Nginx尝试在一个数据包中发送HTTP头部和文件的开头部分。之后,它以完整的数据包发送数据。这减少了发送的数据包数量。
tcp_nodelay
指示Nginx在数据可用时立即发送,无需缓冲。这对于低延迟比最大化吞吐量更重要的交互式应用程序(例如聊天应用程序或实时更新)非常有益。
http {
keepalive_timeout 65; # 保持连接65秒
sendfile on;
tcp_nopush on; # 需要 sendfile on
tcp_nodelay on; # 对代理动态内容有用
}
3. 缓冲区优化
Nginx使用缓冲区来处理来自客户端的请求和来自上游服务器(如应用服务器)的响应。正确调整这些缓冲区的大小可以防止不必要的磁盘I/O,减少内存使用,并提高吞吐量。
客户端缓冲区
client_body_buffer_size:用于客户端请求体的缓冲区大小。如果请求体超过此大小,则会被写入临时文件。client_header_buffer_size:用于客户端请求的第一行和头部的缓冲区大小。large_client_header_buffers:定义用于读取客户端请求头部的较大缓冲区的数量和大小。对于包含许多cookie或长referer头的请求很有用。
代理缓冲区(用于反向代理设置)
proxy_buffers:用于读取来自代理服务器响应的缓冲区的数量和大小。proxy_buffer_size:用于读取响应的第一个缓冲区的大小。通常较小,因为它通常只包含头部。proxy_busy_buffers_size:在任何给定时间可以处于“忙”状态(正在发送给客户端)的最大响应缓冲区量。
FastCGI缓冲区(用于PHP-FPM等)
fastcgi_buffers:用于读取来自FastCGI服务器响应的缓冲区的数量和大小。fastcgi_buffer_size:用于读取响应的第一个缓冲区的大小。
http {
# 客户端缓冲区
client_body_buffer_size 1M; # 根据预期的请求体大小(例如文件上传)调整
client_header_buffer_size 1k;
large_client_header_buffers 4 8k; # 4个缓冲区,每个8KB
# 代理缓冲区(如果Nginx充当反向代理)
proxy_buffers 8 16k; # 8个缓冲区,每个16KB
proxy_buffer_size 16k; # 第一个缓冲区16KB
proxy_busy_buffers_size 16k; # 最大16KB的忙缓冲区
# FastCGI缓冲区(如果Nginx与PHP-FPM配合使用)
fastcgi_buffers 16 16k; # 许多PHP-FPM应用程序的起点
fastcgi_buffer_size 16k; # 第一个缓冲区16KB
}
警告: 将缓冲区设置得太小可能导致磁盘I/O和性能下降。设置得太大可能消耗过多内存。通过测试找到平衡点。
4. 实施强大的缓存策略
缓存是提高性能和减少后端服务器负载的最有效方法之一。Nginx可以充当强大的内容缓存。
proxy_cache_path
定义缓存目录的路径、大小、子目录级别数以及非活动项目在缓存中保留的时间。
proxy_cache
为给定的location块激活缓存,引用在proxy_cache_path中定义的区域。
proxy_cache_valid
设置Nginx应缓存具有特定HTTP状态码的响应的时间。
proxy_cache_revalidate
启用后,Nginx将使用If-Modified-Since和If-None-Match头与后端重新验证缓存内容,从而减少带宽使用。
proxy_cache_use_stale
指示Nginx在后端服务器宕机、无响应或遇到错误时提供过期的缓存内容。这大大提高了可用性。
expires
为静态文件的客户端缓存设置Cache-Control和Expires头。这最大限度地减少了对Nginx的重复请求。
http {
# 在http块中定义代理缓存区域
proxy_cache_path /var/cache/nginx/my_cache levels=1:2 keys_zone=my_cache:10m inactive=60m max_size=10g;
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://my_upstream_backend;
proxy_cache my_cache; # 为此位置启用缓存
proxy_cache_valid 200 302 10m; # 缓存成功响应10分钟
proxy_cache_valid 404 1m; # 缓存404响应1分钟
proxy_cache_revalidate on;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
add_header X-Cache-Status $upstream_cache_status; # 有助于调试
}
# 在浏览器中长时间缓存静态文件
location ~* \.(jpg|jpeg|gif|png|css|js|ico|woff|woff2|ttf|svg|eot)$ {
expires 30d; # 缓存30天
add_header Cache-Control "public, no-transform";
# 对于静态文件,如果未代理,考虑直接从Nginx提供
root /var/www/html;
}
}
}
5. 启用Gzip压缩
在将响应发送给客户端之前进行压缩,可以显著减少带宽使用并改善页面加载时间,尤其是对于基于文本的内容。
gzip on
激活gzip压缩。
gzip_comp_level
设置压缩级别(1-9)。级别1最快但压缩率最低;级别9最慢但压缩率最高。级别6通常提供良好的平衡。
gzip_types
指定应压缩的MIME类型。包括常见的文本、CSS、JavaScript和JSON类型。
gzip_min_length
设置应启用压缩的响应最小长度(以字节为单位)。小文件受益不大,甚至可能因压缩开销而变慢。
gzip_proxied
指示Nginx即使响应是代理的也要进行压缩。any是一个常见值。
gzip_vary
向响应添加Vary: Accept-Encoding头,通知代理响应可能因Accept-Encoding请求头而异。
http {
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6; # 压缩级别1-9(6是一个很好的平衡点)
gzip_buffers 16 8k; # 16个缓冲区,每个8KB
gzip_http_version 1.1; # 压缩的最低HTTP版本
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml;
gzip_min_length 1000; # 仅压缩大于1KB的响应
}
6. 优化日志记录
虽然日志对于监控和故障排除至关重要,但过多或未经优化的日志记录可能会引入显著的磁盘I/O,尤其是在高流量站点上。
access_log
- 禁用静态资源的日志:对于高访问量的静态内容(图片、CSS、JS),禁用
access_log可以节省大量I/O。 - 缓冲:Nginx可以在将日志条目写入磁盘之前在内存中缓冲它们,从而减少磁盘写入的频率。这里使用
buffer和flush参数。
error_log
设置适当的日志记录级别(crit、error、warn、info、debug)。对于生产环境,warn或error通常足以捕获关键问题,而不会淹没日志。
http {
server {
# 动态内容的默认访问日志
access_log /var/log/nginx/access.log main;
location ~* \.(jpg|jpeg|gif|png|css|js|ico|woff|woff2|ttf|svg|eot)$ {
access_log off; # 禁用常见静态文件的日志记录
expires 30d;
}
}
# 主HTTP上下文的缓冲访问日志示例
# access_log /var/log/nginx/access.log main buffer=16k flush=5s;
error_log /var/log/nginx/error.log warn; # 仅记录警告及以上级别
}
7. 调整超时时间
适当配置的超时时间可以防止Nginx长时间持有非活动连接,从而释放资源。
客户端超时
client_body_timeout:Nginx等待客户端发送请求体的时间。client_header_timeout:Nginx等待客户端发送请求头部的时间。send_timeout:Nginx在发送响应后等待客户端接受的时间。
代理/FastCGI超时(如果适用)
proxy_connect_timeout:与代理服务器建立连接的超时时间。proxy_send_timeout:向代理服务器传输请求的超时时间。proxy_read_timeout:从代理服务器读取响应的超时时间。
http {
client_body_timeout 15s; # 客户端有15秒发送请求体
client_header_timeout 15s; # 客户端有15秒发送头部
send_timeout 15s; # Nginx有15秒向客户端发送响应
# 代理场景
proxy_connect_timeout 5s; # 5秒连接到上游
proxy_send_timeout 15s; # 15秒向上游发送请求
proxy_read_timeout 15s; # 15秒从上游读取响应
# FastCGI场景
fastcgi_connect_timeout 5s;
fastcgi_send_timeout 15s;
fastcgi_read_timeout 15s;
}
8. SSL/TLS优化
对于启用HTTPS的站点,优化SSL/TLS设置对于减少CPU开销和提高握手性能至关重要。
ssl_session_cache 和 ssl_session_timeout
启用SSL会话缓存,以避免对来自同一客户端的后续连接进行计算成本高昂的完整TLS握手。
ssl_protocols 和 ssl_ciphers
使用现代TLS协议,如TLSv1.2和TLSv1.3。小心复制的密码字符串:TLS 1.3密码的控制方式与旧版TLS密码套件不同,发行版的默认设置通常比旧指南中的过时示例更安全。
ssl_stapling
启用OCSP装订,Nginx定期从CA获取OCSP响应并将其“装订”到SSL/TLS握手。这通过避免单独的OCSP查询来减少客户端延迟。
server {
listen 443 ssl;
ssl_certificate /etc/nginx/ssl/your_domain.crt;
ssl_certificate_key /etc/nginx/ssl/your_domain.key;
ssl_session_cache shared:SSL:10m; # 共享缓存,用于10MB的会话数据
ssl_session_timeout 10m; # 会话在10分钟后过期
ssl_protocols TLSv1.2 TLSv1.3; # 使用现代、安全的协议
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305';
ssl_prefer_server_ciphers on;
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 8.8.8.8 valid=300s; # 使用适合您环境的解析器
resolver_timeout 5s;
}
9. 打开文件缓存
Nginx可以缓存频繁访问文件的文件描述符,从而减少重复的系统调用来打开和关闭文件。
open_file_cache
启用缓存,指定最大元素数以及非活动元素保留的时间。
open_file_cache_valid
设置缓存检查其元素有效性的频率。
open_file_cache_min_uses
指定在inactive时间内文件必须被访问的最小次数,才能保留在缓存中。
open_file_cache_errors
决定Nginx是否应缓存打开文件时的错误。
http {
open_file_cache max=100000 inactive=60s; # 缓存最多100,000个文件描述符60秒
open_file_cache_valid 80s; # 每80秒检查一次有效性
open_file_cache_min_uses 1; # 缓存至少使用过一次的文件
open_file_cache_errors on; # 缓存与文件打开相关的错误
}
10. 使用真实流量信号进行验证
清单上的最后一项是测量。在进行更改之前,捕获一个小的基线:请求延迟、5xx率、活动连接、CPU、内存、磁盘I/O、网络吞吐量和上游响应时间。更改后,比较相同的数字。
对于反向代理,$request_time和$upstream_response_time特别有用。如果两者同时上升,则后端可能很慢。如果$request_time很高而上游时间很低或为空,请检查客户端上传速度、响应传输时间、缓冲、压缩或静态文件交付。如果这两个指标都无法解释问题,请检查错误日志和操作系统。
最安全的调优顺序很简单:使用nginx -t测试配置,尽可能重新加载而不是重启,监控日志,如果延迟或错误朝错误方向发展,则快速回滚。Nginx可以处理大量流量,但前提是其限制、内核和上游应用程序相互协调。