深入理解 Nginx 缓存机制与性能优化
本文是 Nginx 实操专栏的第六篇,我们将深入探讨 Nginx 的缓存机制、各种缓存策略以及性能优化技巧,帮助你构建更快速、更高效的 Web 应用。
引言
在现代 Web 应用中,性能优化是一个永恒的话题。用户期望页面能够快速加载,而缓存技术是提升性能的关键手段之一。Nginx 作为一个高性能的 Web 服务器和反向代理,提供了强大的缓存功能。
在本文中,我们将详细介绍 Nginx 的缓存机制,包括静态资源缓存、反向代理缓存,以及各种性能优化技巧。
缓存基础概念
什么是缓存?
缓存是一种临时存储机制,用于存储经常访问的数据副本,以便后续请求可以更快地获取这些数据,而无需重新计算或从原始源获取。
缓存的类型
- 浏览器缓存 - 客户端浏览器存储的资源副本
- 代理缓存 - 中间代理服务器存储的资源副本
- 应用缓存 - 应用服务器端的缓存
- CDN 缓存 - 内容分发网络中的缓存
缓存的优势
- 减少延迟 - 从缓存中获取数据比从原始源获取更快
- 降低带宽消耗 - 减少重复数据传输
- 减轻服务器负载 - 减少对后端服务器的请求
- 提高可用性 - 即使原始服务器不可用,缓存仍可提供服务
静态资源缓存
静态资源(如图片、CSS、JavaScript 文件)是缓存的主要对象。
基本缓存配置
nginx
server {
listen 80;
server_name example.com;
root /var/www/example.com;
# 图片资源缓存
location ~* \.(jpg|jpeg|png|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
add_header Vary Accept-Encoding;
}
# CSS 和 JavaScript 资源缓存
location ~* \.(css|js)$ {
expires 1y;
add_header Cache-Control "public, immutable";
add_header Vary Accept-Encoding;
}
# 字体文件缓存
location ~* \.(woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public";
add_header Vary Accept-Encoding;
}
# 其他静态资源
location /static/ {
expires 1M;
add_header Cache-Control "public";
}
}缓存控制头详解
Expires 头
nginx
expires 1y; # 1年
expires 30d; # 30天
expires 12h; # 12小时
expires 30m; # 30分钟
expires 10s; # 10秒
expires epoch; # 立即过期
expires max; # 最大过期时间
expires off; # 禁用 expiresCache-Control 头
nginx
# 公共缓存,可以被任何缓存存储
add_header Cache-Control "public";
# 私有缓存,只能被浏览器缓存
add_header Cache-Control "private";
# 不缓存
add_header Cache-Control "no-cache, no-store, must-revalidate";
# 不变缓存,表示资源不会改变
add_header Cache-Control "public, immutable";
# 缓存但需要验证
add_header Cache-Control "public, must-revalidate";ETag 和 Last-Modified
Nginx 自动为静态资源生成 ETag 和 Last-Modified 头:
nginx
# 启用 ETag
etag on;
# 启用 Last-Modified
if_modified_since exact;反向代理缓存
Nginx 可以缓存后端服务器的响应,减少对后端的请求。
基本代理缓存配置
nginx
# 定义缓存路径和参数
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m use_temp_path=off;
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://backend;
proxy_cache my_cache;
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_cache_lock on;
# 添加缓存状态头
add_header X-Cache-Status $upstream_cache_status;
}
}缓存路径参数详解
nginx
proxy_cache_path /var/cache/nginx
levels=1:2 # 目录层级结构
keys_zone=my_cache:10m # 共享内存区域名称和大小
max_size=10g # 缓存最大大小
inactive=60m # 60分钟未访问的缓存将被清除
use_temp_path=off # 不使用临时路径
loader_sleep=50ms # 加载器睡眠时间
loader_files=1000; # 每次加载的文件数缓存有效性控制
nginx
# 根据响应状态码设置不同的缓存时间
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
proxy_cache_valid any 1m;
# 根据请求方法设置缓存
proxy_cache_methods GET HEAD POST;
# 根据内容类型设置缓存
map $sent_http_content_type $no_cache_types {
default 0;
"text/html" 1;
"application/json" 1;
}
proxy_cache_valid 200 1h;
proxy_cache_valid 404 1m;
proxy_no_cache $no_cache_types;缓存键定制
nginx
# 自定义缓存键
proxy_cache_key "$scheme$request_method$host$request_uri";
# 包含更多变量的缓存键
proxy_cache_key "$scheme$request_method$host$request_uri$http_accept_language$http_accept_encoding";
# 对于 API 请求,可能需要忽略查询参数顺序
proxy_cache_key "$scheme$request_method$host$uri";缓存状态监控
nginx
# 添加缓存状态头
add_header X-Cache-Status $upstream_cache_status;
# 更详细的缓存信息
add_header X-Cache-Key $request_uri;
add_header X-Cache-Host $upstream_addr;高级缓存策略
分层缓存
nginx
# L1 缓存 - 内存缓存
proxy_cache_path /var/cache/nginx/l1 levels=1:2 keys_zone=l1_cache:100m max_size=1g inactive=10m;
# L2 缓存 - 磁盘缓存
proxy_cache_path /var/cache/nginx/l2 levels=1:2 keys_zone=l2_cache:500m max_size=10g inactive=1h;
upstream backend {
server backend1.example.com;
server backend2.example.com;
}
server {
listen 80;
server_name example.com;
location /api/fast-changing/ {
proxy_pass http://backend;
proxy_cache l1_cache;
proxy_cache_valid 200 1m;
add_header X-Cache-Level L1;
}
location /api/slow-changing/ {
proxy_pass http://backend;
proxy_cache l2_cache;
proxy_cache_valid 200 1h;
add_header X-Cache-Level L2;
}
}条件缓存
nginx
# 根据用户角色决定是否缓存
map $http_authorization $no_cache {
default 0;
"~*admin" 1;
}
server {
location / {
proxy_pass http://backend;
proxy_cache my_cache;
proxy_cache_valid 200 1h;
proxy_no_cache $no_cache;
proxy_cache_bypass $no_cache;
}
}缓存预热
nginx
# 定期预热缓存
location /warm-cache {
internal;
proxy_pass http://backend;
proxy_cache my_cache;
proxy_cache_valid 200 1h;
}Gzip 压缩优化
压缩可以显著减少传输数据量,提高页面加载速度。
基本 Gzip 配置
nginx
# 启用 gzip 压缩
gzip on;
# 启用对 HTTP/1.1 的 gzip 压缩
gzip_http_version 1.1;
# 启用对代理请求的 gzip 压缩
gzip_proxied any;
# 设置 Vary 头
gzip_vary on;
# 设置压缩级别(1-9,数字越大压缩比越高但消耗更多 CPU)
gzip_comp_level 6;
# 设置最小压缩文件大小
gzip_min_length 1024;
# 设置需要压缩的 MIME 类型
gzip_types
text/plain
text/css
text/xml
text/javascript
application/json
application/javascript
application/xml+rss
application/atom+xml
image/svg+xml;预压缩静态文件
对于不经常变化的静态文件,可以预先压缩并使用 [gzip_static] 指令:
nginx
location ~* \.(css|js|html|xml)$ {
gzip_static on;
expires 1y;
add_header Cache-Control "public, immutable";
}预压缩文件需要手动创建或使用构建工具生成,文件名以 .gz 结尾:
style.css
style.css.gz性能优化技巧
连接优化
nginx
# 启用 sendfile
sendfile on;
# 启用 tcp_nopush
tcp_nopush on;
# 启用 tcp_nodelay
tcp_nodelay on;
# 设置 keepalive 超时时间
keepalive_timeout 65;
# 设置客户端请求体缓冲区大小
client_body_buffer_size 128k;
# 设置客户端请求头缓冲区大小
client_header_buffer_size 1k;
large_client_header_buffers 4 4k;工作进程优化
nginx
# 设置工作进程数
worker_processes auto;
# 设置每个工作进程的最大连接数
events {
worker_connections 1024;
use epoll;
multi_accept on;
}
# 设置工作进程 CPU 亲和性
worker_cpu_affinity auto;缓冲区优化
nginx
# 设置代理缓冲区
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
proxy_busy_buffers_size 8k;
# 设置 FastCGI 缓冲区
fastcgi_buffering on;
fastcgi_buffer_size 4k;
fastcgi_buffers 8 4k;
fastcgi_busy_buffers_size 8k;缓存管理
缓存清除
虽然 Nginx Plus 提供了缓存清除 API,但开源版本需要通过其他方式实现:
nginx
# 使用第三方模块 nginx-cache-purge
location ~ /purge(/.*) {
proxy_cache_purge my_cache $scheme$request_method$host$1;
}或者通过脚本删除缓存文件:
bash
# 删除特定 URL 的缓存
find /var/cache/nginx -name "*$(echo -n 'http://example.com/some/path' | md5sum | cut -d' ' -f1)*" -delete缓存监控
nginx
# 启用缓存状态页面
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
# 自定义缓存监控
location /cache_status {
access_log off;
allow 127.0.0.1;
deny all;
# 返回缓存统计信息
return 200 "Cache zone: my_cache\nCache size: $upstream_cache_status";
}实际应用示例
综合优化配置
nginx
# 定义缓存路径
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:100m max_size=10g inactive=60m use_temp_path=off;
# 启用 gzip 压缩
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_comp_level 6;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/json
application/javascript
application/xml+rss
application/atom+xml
image/svg+xml;
server {
listen 80;
server_name example.com;
root /var/www/example.com;
# 静态资源缓存
location ~* \.(jpg|jpeg|png|gif|ico|svg|css|js|woff|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
add_header Vary Accept-Encoding;
# 预压缩文件支持
gzip_static on;
}
# API 缓存
location /api/ {
proxy_pass http://backend;
proxy_cache my_cache;
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_cache_lock on;
# 添加缓存状态头
add_header X-Cache-Status $upstream_cache_status;
# 代理头设置
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_set_header X-Forwarded-Proto $scheme;
}
# 动态内容不缓存
location ~* \.(php|jsp|asp)$ {
proxy_pass http://backend;
proxy_cache_bypass 1;
proxy_no_cache 1;
}
}最佳实践总结
1. 缓存策略选择
nginx
# 静态资源 - 长期缓存
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# HTML 页面 - 短期缓存或不缓存
location ~* \.html$ {
expires 1h;
add_header Cache-Control "public, must-revalidate";
}
# API 响应 - 根据内容类型设置缓存时间
location /api/ {
proxy_pass http://backend;
proxy_cache my_cache;
proxy_cache_valid 200 10m;
proxy_cache_valid 404 1m;
}2. 性能优化配置
nginx
# 全局性能优化
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
# 缓冲区优化
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
# 工作进程优化
worker_processes auto;
worker_connections 1024;
worker_cpu_affinity auto;3. 安全的缓存配置
nginx
# 避免缓存敏感内容
location ~* (login|admin|user) {
proxy_pass http://backend;
proxy_cache_bypass 1;
proxy_no_cache 1;
}
# 根据认证状态决定是否缓存
map $http_authorization $no_cache {
default 0;
"~*" 1;
}
location / {
proxy_pass http://backend;
proxy_cache my_cache;
proxy_no_cache $no_cache;
proxy_cache_bypass $no_cache;
}总结
通过合理配置 Nginx 的缓存机制和性能优化参数,我们可以显著提升 Web 应用的响应速度和用户体验。关键要点包括:
- 针对不同类型的内容设置合适的缓存策略
- 合理配置代理缓存以减少后端负载
- 启用 Gzip 压缩以减少传输数据量
- 优化连接和缓冲区参数以提高性能
- 定期监控和管理缓存以确保其有效性
在下一章中,我们将探讨 Nginx 与前端应用的集成,特别是如何支持 SPA(单页应用)和实现前端路由。
要点回顾:
- 静态资源缓存通过设置适当的 Expires 和 Cache-Control 头实现
- 反向代理缓存可以显著减少对后端服务器的请求
- Gzip 压缩和预压缩可以减少传输数据量
- 合理的连接和缓冲区配置可以提高性能
- 缓存管理和监控对于维护缓存系统的健康运行至关重要