
一、概述
1.1 背景介绍
2024年初接手过一个内容平台项目,PHP渲染的页面,平均响应时间800ms,一到流量高峰后端服务就告警。加了两台服务器问题依旧,因为瓶颈在数据库查询和页面渲染上,横向扩展解决不了根本问题。
后来花了一天时间在Nginx层加上proxy_cache,同样的页面响应时间直接降到5ms以内,后端请求量下降90%。这就是缓存的威力——把重复的计算结果存起来,下次直接返回,不用再算一遍。
Nginx的proxy_cache是反向代理缓存,位于客户端和后端服务之间。当请求第一次到达时,Nginx转发给后端,拿到响应后存一份在本地磁盘/内存;后续相同请求直接从缓存返回,不再打扰后端。这个机制适合所有读多写少的场景:新闻资讯、商品详情、API数据等。
1.2 技术特点
Nginx proxy_cache的核心优势:
性能极高:缓存在本地,没有网络开销,响应时间毫秒级 配置灵活:可以根据URL、Header、Cookie等多维度控制缓存策略 节省带宽:支持条件请求(304 Not Modified),减少重复传输 分级存储:支持内存+磁盘混合存储,热点数据在内存,长尾在磁盘 缓存验证:支持后端验证(proxy_cache_revalidate),保证数据新鲜度 原生支持:标准模块,不需要额外安装
和Redis/Memcached缓存相比,proxy_cache的特点是:离用户更近(在Nginx层),延迟更低,但不支持分布式(每台Nginx独立缓存)。适合单机或配合CDN使用。
1.3 适用场景
1.4 环境要求
二、详细步骤
2.1 准备工作
2.1.1 创建缓存目录
# 创建缓存主目录
mkdir -p /var/cache/nginx/proxy_cache
# 如果要用内存缓存(推荐用于热点数据)
mkdir -p /var/cache/nginx/memory_cache
mount -t tmpfs -o size=2G tmpfs /var/cache/nginx/memory_cache
# 设置持久化挂载(可选)
echo "tmpfs /var/cache/nginx/memory_cache tmpfs size=2G,mode=0755 0 0" >> /etc/fstab
# 设置权限
chown -R nginx:nginx /var/cache/nginx
chmod -R 755 /var/cache/nginx
2.1.2 检查磁盘性能
# 测试磁盘写入速度(缓存性能瓶颈通常在这里)
dd if=/dev/zero of=/var/cache/nginx/test.bin bs=1M count=1024 conv=fdatasync
# SSD建议:> 200MB/s
# HDD建议:> 50MB/s
# 如果低于这个值,考虑使用内存缓存或更换磁盘
# 清理测试文件
rm -f /var/cache/nginx/test.bin
2.1.3 规划缓存容量
# 计算缓存大小规划:
#
# 假设:
# - 平均响应大小:50KB
# - 预计缓存10万个URL
# - 所需空间:50KB × 100,000 = 5GB
#
# 建议配置:
# - max_size:略大于预计使用量,比如8GB
# - inactive:根据内容更新频率,通常1-7天
# - keys_zone:每1MB大约存储8000个key
# 查看磁盘空间
df -h /var/cache/nginx
2.2 核心配置
2.2.1 定义缓存区域
在http块中定义缓存路径和参数:
# /etc/nginx/nginx.conf
http {
# 磁盘缓存区域定义
# path: 缓存文件存储路径
# levels: 目录层级,1:2表示一级目录1个字符,二级目录2个字符
# keys_zone: 缓存索引存放在共享内存,名称:大小
# max_size: 缓存文件最大占用磁盘空间
# inactive: 多久没有被访问就删除
# use_temp_path: 是否使用临时目录,off表示直接写入缓存目录,减少IO
proxy_cache_path /var/cache/nginx/proxy_cache
levels=1:2
keys_zone=my_cache:100m
max_size=10g
inactive=7d
use_temp_path=off;
# 内存缓存区域(用于热点数据)
proxy_cache_path /var/cache/nginx/memory_cache
levels=1:2
keys_zone=hot_cache:50m
max_size=2g
inactive=1h
use_temp_path=off;
# API专用缓存区域(较短过期时间)
proxy_cache_path /var/cache/nginx/api_cache
levels=1:2
keys_zone=api_cache:50m
max_size=5g
inactive=10m
use_temp_path=off;
# ... 其他配置
}
levels参数详解:
# levels=1:2 表示:
# URL: http://example.com/path/to/resource
# MD5: d41d8cd98f00b204e9800998ecf8427e
# 存储路径: /var/cache/nginx/proxy_cache/e/27/d41d8cd98f00b204e9800998ecf8427e
# ^ ^
# | |__ 二级目录(2个字符)
# |____ 一级目录(1个字符)
# 为什么要分级?
# 避免单目录下文件过多导致文件系统性能下降
# ext4单目录超过10万文件性能会明显下降
2.2.2 配置缓存规则
# /etc/nginx/conf.d/cache.example.com.conf
# 定义缓存key
# 默认是 $scheme$proxy_host$request_uri
# 可以根据需要自定义,比如忽略某些参数
proxy_cache_key "$scheme$host$request_uri";
# 根据响应码设置不同缓存时间
proxy_cache_valid 200 301 302 1h;
proxy_cache_valid 404 1m;
proxy_cache_valid any 10s; # 其他状态码
server {
listen 80;
server_name example.com;
# 启用缓存
proxy_cache my_cache;
# 缓存锁,防止缓存击穿(同一时刻只有一个请求穿透到后端)
proxy_cache_lock on;
proxy_cache_lock_timeout 5s;
proxy_cache_lock_age 5s;
# 使用过期缓存的场景
# error: 后端错误时返回旧缓存
# timeout: 后端超时时返回旧缓存
# updating: 正在更新缓存时返回旧缓存
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
# 后台异步更新缓存
proxy_cache_background_update on;
# 请求N次后才缓存(过滤一次性请求)
proxy_cache_min_uses 2;
# 添加缓存状态响应头(调试用)
add_header X-Cache-Status $upstream_cache_status;
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# 这个location使用默认缓存配置
}
# API接口使用专用缓存
location /api/ {
proxy_cache api_cache;
proxy_cache_valid 200 1m; # API缓存1分钟
# 不同参数缓存不同内容
proxy_cache_key "$scheme$host$request_uri";
# 某些情况不缓存
proxy_cache_bypass $http_authorization; # 有认证头不走缓存
proxy_no_cache $http_authorization; # 有认证头不存缓存
proxy_pass http://api_backend;
}
# 用户相关接口不缓存
location /api/user/ {
proxy_cache off;
proxy_pass http://api_backend;
}
# 静态资源长时间缓存
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2|woff|ttf)$ {
proxy_cache my_cache;
proxy_cache_valid 200 30d;
expires 30d;
proxy_pass http://static_backend;
}
}
2.2.3 缓存状态说明
$upstream_cache_status变量的可能值:
2.3 启动和验证
2.3.1 配置检查
# 检查配置语法
nginx -t
# 查看缓存相关配置
nginx -T | grep -E "proxy_cache|cache_path"
2.3.2 重载配置
# 平滑重载
nginx -s reload
# 查看缓存目录是否正常创建
ls -la /var/cache/nginx/
2.3.3 验证缓存效果
# 第一次请求(应该是MISS)
curl -I http://example.com/api/test
# 观察 X-Cache-Status: MISS
# 第二次请求(如果配置了min_uses=2,还是MISS)
curl -I http://example.com/api/test
# 第三次请求(应该是HIT)
curl -I http://example.com/api/test
# 观察 X-Cache-Status: HIT
# 查看缓存文件
find /var/cache/nginx/proxy_cache -type f | head -10
# 查看缓存文件内容(调试)
head -50 /var/cache/nginx/proxy_cache/e/27/xxx
2.3.4 性能测试对比
# 不走缓存的性能
ab -n 1000 -c 50 -H "Cache-Control: no-cache" http://example.com/api/test
# 走缓存的性能
ab -n 1000 -c 50 http://example.com/api/test
# 对比两次测试的:
# - Requests per second(每秒请求数)
# - Time per request(平均响应时间)
#
# 正常情况下,缓存命中的QPS应该是未命中的10-100倍
三、示例代码和配置
3.1 完整配置示例
# /etc/nginx/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /run/nginx.pid;
events {
worker_connections 65535;
use epoll;
multi_accept on;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# 日志格式(包含缓存状态)
log_format cache_log '$remote_addr - [$time_local] "$request" '
'$status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'cache:$upstream_cache_status '
'rt:$request_time upt:$upstream_response_time';
access_log /var/log/nginx/access.log cache_log;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
# Gzip压缩
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 5;
gzip_types text/plain text/css text/xml application/json application/javascript application/xml;
# ==================== 缓存配置开始 ====================
# 主缓存区域(通用内容)
proxy_cache_path /var/cache/nginx/main_cache
levels=1:2
keys_zone=main_cache:100m
max_size=20g
inactive=7d
use_temp_path=off;
# 内存缓存区域(热点内容)
proxy_cache_path /var/cache/nginx/hot_cache
levels=1:2
keys_zone=hot_cache:50m
max_size=2g
inactive=1h
use_temp_path=off;
# API缓存区域
proxy_cache_path /var/cache/nginx/api_cache
levels=1:2
keys_zone=api_cache:50m
max_size=5g
inactive=10m
use_temp_path=off;
# 静态资源缓存区域
proxy_cache_path /var/cache/nginx/static_cache
levels=1:2
keys_zone=static_cache:100m
max_size=50g
inactive=30d
use_temp_path=off;
# 全局缓存设置
proxy_cache_lock on;
proxy_cache_lock_timeout 5s;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_cache_background_update on;
proxy_cache_revalidate on;
# ==================== 缓存配置结束 ====================
# 后端服务器组
upstream backend {
least_conn;
server 10.0.0.11:8080 weight=5;
server 10.0.0.12:8080 weight=5;
keepalive 100;
}
upstream api_backend {
least_conn;
server 10.0.0.21:8080;
server 10.0.0.22:8080;
keepalive 50;
}
upstream static_backend {
server 10.0.0.31:80;
server 10.0.0.32:80;
keepalive 100;
}
include /etc/nginx/conf.d/*.conf;
}
# /etc/nginx/conf.d/www.example.com.conf
# 定义不缓存的条件
map $request_uri $skip_cache {
default 0;
~*/admin/ 1; # 后台不缓存
~*/api/user/ 1; # 用户接口不缓存
~*/api/cart/ 1; # 购物车不缓存
~*/api/order/ 1; # 订单不缓存
}
# 根据Cookie判断是否跳过缓存
map $http_cookie $skip_cache_cookie {
default 0;
~*session_id 1; # 有session不缓存
~*user_token 1; # 有token不缓存
}
server {
listen 80;
listen 443 ssl http2;
server_name www.example.com;
ssl_certificate /etc/nginx/ssl/example.com.crt;
ssl_certificate_key /etc/nginx/ssl/example.com.key;
# 缓存调试头
add_header X-Cache-Status $upstream_cache_status always;
add_header X-Cache-Key $scheme$host$request_uri always;
# 根路径
location / {
proxy_cache main_cache;
proxy_cache_key "$scheme$host$request_uri";
proxy_cache_valid 200 301 302 10m;
proxy_cache_valid 404 1m;
proxy_cache_min_uses 1;
# 跳过缓存条件
set $no_cache 0;
if ($skip_cache) {
set $no_cache 1;
}
if ($skip_cache_cookie) {
set $no_cache 1;
}
proxy_cache_bypass $no_cache;
proxy_no_cache $no_cache;
proxy_pass http://backend;
proxy_http_version 1.1;
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;
proxy_set_header Connection "";
# 超时设置
proxy_connect_timeout 10s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
}
# 热门页面(使用内存缓存)
location ~ ^/(hot|trending|popular) {
proxy_cache hot_cache;
proxy_cache_key "$scheme$host$request_uri";
proxy_cache_valid 200 5m;
proxy_cache_min_uses 1;
# 热点内容即使过期也返回
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# 公开API(带缓存)
location /api/public/ {
proxy_cache api_cache;
proxy_cache_key "$scheme$host$request_uri";
proxy_cache_valid 200 2m;
proxy_cache_valid 404 30s;
# 尊重后端的Cache-Control头
proxy_cache_valid any 0;
proxy_ignore_headers Set-Cookie;
proxy_hide_header Set-Cookie;
proxy_pass http://api_backend;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# 需要认证的API(不缓存)
location /api/ {
proxy_cache off;
proxy_pass http://api_backend;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Authorization $http_authorization;
}
# 静态资源(长期缓存)
location ~* \.(jpg|jpeg|png|gif|ico|svg|webp)$ {
proxy_cache static_cache;
proxy_cache_key "$host$request_uri";
proxy_cache_valid 200 30d;
proxy_cache_min_uses 1;
# 浏览器缓存
expires 30d;
add_header Cache-Control "public, immutable";
add_header X-Cache-Status $upstream_cache_status;
proxy_pass http://static_backend;
proxy_set_header Host $host;
}
location ~* \.(css|js|woff2|woff|ttf|eot)$ {
proxy_cache static_cache;
proxy_cache_key "$host$request_uri";
proxy_cache_valid 200 7d;
expires 7d;
add_header Cache-Control "public";
add_header X-Cache-Status $upstream_cache_status;
proxy_pass http://static_backend;
proxy_set_header Host $host;
}
# 视频/大文件(缓存+限速)
location ~* \.(mp4|avi|mkv|zip|tar\.gz)$ {
proxy_cache static_cache;
proxy_cache_key "$host$request_uri";
proxy_cache_valid 200 30d;
proxy_cache_min_uses 3; # 访问3次才缓存
# 限速,防止带宽被占满
limit_rate 2m;
limit_rate_after 10m; # 前10MB不限速
proxy_pass http://static_backend;
proxy_set_header Host $host;
}
# 健康检查(不缓存不记日志)
location /health {
access_log off;
proxy_cache off;
proxy_pass http://backend;
}
# 缓存清理接口(需要配合ngx_cache_purge模块)
location ~ /purge(/.*) {
# 限制访问
allow 127.0.0.1;
allow 10.0.0.0/8;
deny all;
proxy_cache_purge main_cache "$scheme$host$1";
}
}
3.2 实际应用案例
案例一:新闻资讯站点缓存策略
新闻站点的特点:首页更新频繁,文章页面发布后很少修改,图片永远不变。
# /etc/nginx/conf.d/news.example.com.conf
server {
listen 80;
server_name news.example.com;
# 首页(短缓存+及时更新)
location = / {
proxy_cache hot_cache;
proxy_cache_key "$host$request_uri";
proxy_cache_valid 200 1m; # 只缓存1分钟
# 缓存正在更新时返回旧内容,保证用户体验
proxy_cache_use_stale updating;
proxy_cache_background_update on;
proxy_pass http://backend;
add_header X-Cache-Status $upstream_cache_status;
}
# 文章列表页(较短缓存)
location ~ ^/category/ {
proxy_cache main_cache;
proxy_cache_key "$host$request_uri$arg_page"; # 带分页参数
proxy_cache_valid 200 5m;
proxy_pass http://backend;
add_header X-Cache-Status $upstream_cache_status;
}
# 文章详情页(较长缓存)
location ~ ^/article/\d+ {
proxy_cache main_cache;
proxy_cache_key "$host$request_uri";
proxy_cache_valid 200 1h; # 缓存1小时
# 支持条件请求,减少传输
proxy_cache_revalidate on;
proxy_pass http://backend;
add_header X-Cache-Status $upstream_cache_status;
}
# 图片永久缓存
location /uploads/ {
proxy_cache static_cache;
proxy_cache_key "$host$request_uri";
proxy_cache_valid 200 365d;
expires max;
add_header Cache-Control "public, immutable";
proxy_pass http://static_backend;
}
}
案例二:电商商品缓存策略
电商的挑战:商品信息要相对实时(库存、价格),但又要承受大流量。
# /etc/nginx/conf.d/shop.example.com.conf
# 定义商品ID提取
map $request_uri $product_id {
~^/product/(\d+) $1;
default "";
}
server {
listen 80;
server_name shop.example.com;
# 商品详情页(HTML部分缓存)
location ~ ^/product/\d+ {
proxy_cache main_cache;
proxy_cache_key "$host$request_uri";
proxy_cache_valid 200 5m;
# 后台更新商品时主动清缓存
proxy_cache_use_stale updating;
proxy_cache_background_update on;
proxy_pass http://backend;
add_header X-Cache-Status $upstream_cache_status;
add_header X-Product-ID $product_id;
}
# 商品实时数据API(短缓存或不缓存)
location ~ ^/api/product/\d+/realtime {
proxy_cache api_cache;
proxy_cache_key "$host$request_uri";
proxy_cache_valid 200 10s; # 只缓存10秒
proxy_pass http://api_backend;
add_header X-Cache-Status $upstream_cache_status;
}
# 商品基础信息API(较长缓存)
location ~ ^/api/product/\d+/info {
proxy_cache api_cache;
proxy_cache_key "$host$request_uri";
proxy_cache_valid 200 10m;
proxy_pass http://api_backend;
add_header X-Cache-Status $upstream_cache_status;
}
# 分类页面(分页缓存)
location ~ ^/category/\d+ {
proxy_cache main_cache;
# 包含排序和分页参数
proxy_cache_key "$host$request_uri$arg_sort$arg_page$arg_pageSize";
proxy_cache_valid 200 10m;
proxy_pass http://backend;
}
# 搜索结果(参数化缓存)
location /search {
proxy_cache api_cache;
# 关键词+筛选条件+分页
proxy_cache_key "$host$uri$arg_q$arg_category$arg_price_min$arg_price_max$arg_page";
proxy_cache_valid 200 5m;
proxy_cache_min_uses 2; # 至少搜2次才缓存
proxy_pass http://api_backend;
}
# 购物车和订单(绝对不缓存)
location ~ ^/(cart|order|checkout) {
proxy_cache off;
proxy_pass http://backend;
}
}
案例三:API网关缓存策略
API网关需要根据不同的接口特性设置不同的缓存策略。
# /etc/nginx/conf.d/api-gateway.conf
# 根据请求方法决定是否缓存
map $request_method $cache_method {
GET 1;
HEAD 1;
default 0;
}
# 根据响应的Cache-Control头决定缓存时间
map $upstream_http_cache_control $custom_cache_time {
default 60s;
~*max-age=(\d+) $1s;
~*no-cache 0;
~*no-store 0;
~*private 0;
}
server {
listen 80;
server_name api.example.com;
# 只缓存GET和HEAD请求
set $no_cache 0;
if ($cache_method = 0) {
set $no_cache 1;
}
# 带Authorization头的不缓存
if ($http_authorization != "") {
set $no_cache 1;
}
# 公开接口
location /v1/public/ {
proxy_cache api_cache;
proxy_cache_key "$host$request_uri";
proxy_cache_valid 200 5m;
proxy_cache_bypass $no_cache;
proxy_no_cache $no_cache;
# 响应头显示缓存信息
add_header X-Cache-Status $upstream_cache_status;
add_header X-Cache-TTL $custom_cache_time;
proxy_pass http://api_backend;
}
# 字典/配置类接口(长缓存)
location /v1/config/ {
proxy_cache api_cache;
proxy_cache_key "$host$request_uri";
proxy_cache_valid 200 1h;
proxy_pass http://api_backend;
add_header X-Cache-Status $upstream_cache_status;
}
# 需要认证的接口(根据用户缓存)
location /v1/user/ {
# 按用户ID缓存(从Header获取)
proxy_cache api_cache;
proxy_cache_key "$host$request_uri$http_x_user_id";
proxy_cache_valid 200 1m;
# 没有用户ID不缓存
if ($http_x_user_id = "") {
set $no_cache 1;
}
proxy_cache_bypass $no_cache;
proxy_no_cache $no_cache;
proxy_pass http://api_backend;
}
# 写接口(POST/PUT/DELETE)
location /v1/ {
# 非GET请求不走上面的location,这里统一处理
proxy_cache off;
proxy_pass http://api_backend;
}
}
四、最佳实践和注意事项
4.1 最佳实践
4.1.1 缓存Key设计原则
# 原则1:Key要包含所有影响响应内容的因素
# 坑:分页参数没加进去,所有页返回相同内容
# 错误
proxy_cache_key "$host$uri";
# 正确
proxy_cache_key "$host$uri$arg_page$arg_pageSize";
# 原则2:Key不要包含无关因素
# 坑:包含了时间戳参数,永远无法命中
# 错误(如果前端加了_t防缓存参数)
proxy_cache_key "$host$request_uri";
# 正确(过滤掉无关参数)
proxy_cache_key "$host$uri$arg_id$arg_type";
# 原则3:Key长度要适中
# 过长的Key会占用更多共享内存
# 默认Key会做MD5,所以实际存储的是32字符的hash
4.1.2 缓存更新策略
# 策略1:TTL过期自动更新
proxy_cache_valid 200 10m; # 10分钟后过期
# 策略2:后台更新(用户无感)
proxy_cache_background_update on; # 过期时后台更新
proxy_cache_use_stale updating; # 更新期间返回旧缓存
# 策略3:主动清理(需要ngx_cache_purge模块)
location ~ /purge(/.*) {
proxy_cache_purge main_cache "$scheme$host$1";
}
# 清理命令:curl http://example.com/purge/api/product/123
# 策略4:根据响应头控制
proxy_cache_revalidate on; # 尊重ETag/Last-Modified
4.1.3 分级缓存架构
# 一级缓存:内存(热点数据)
proxy_cache_path /var/cache/nginx/memory_cache
levels=1:2
keys_zone=level1:50m
max_size=2g
inactive=10m;
# 二级缓存:SSD(温数据)
proxy_cache_path /var/cache/nginx/ssd_cache
levels=1:2
keys_zone=level2:100m
max_size=50g
inactive=1d;
# 三级缓存:HDD(冷数据)
proxy_cache_path /var/cache/nginx/hdd_cache
levels=1:2
keys_zone=level3:200m
max_size=500g
inactive=7d;
# 使用时根据内容热度选择不同缓存
# 热点内容:level1
# 普通内容:level2
# 长尾内容:level3
4.1.4 与CDN配合使用
# Nginx作为源站,配合CDN使用时的配置
server {
listen 80;
server_name origin.example.com;
# 设置合适的Cache-Control头,让CDN缓存
location ~* \.(jpg|png|gif|css|js)$ {
proxy_cache static_cache;
proxy_cache_valid 200 7d;
# CDN缓存7天,浏览器缓存1天
add_header Cache-Control "public, max-age=86400, s-maxage=604800";
add_header X-Cache-Status $upstream_cache_status;
proxy_pass http://backend;
}
# API响应也可以让CDN缓存
location /api/public/ {
proxy_cache api_cache;
proxy_cache_valid 200 5m;
# CDN缓存5分钟
add_header Cache-Control "public, max-age=300";
# 带Vary头,让CDN按这些维度缓存
add_header Vary "Accept-Encoding, Accept-Language";
proxy_pass http://api_backend;
}
}
4.2 注意事项
4.2.1 常见错误
4.2.2 安全注意事项
# 1. 防止敏感信息被缓存
# 带Authorization的请求不缓存
proxy_cache_bypass $http_authorization;
proxy_no_cache $http_authorization;
# 带敏感Cookie的不缓存
map $http_cookie $has_sensitive_cookie {
default 0;
~*session 1;
~*token 1;
}
proxy_cache_bypass $has_sensitive_cookie;
proxy_no_cache $has_sensitive_cookie;
# 2. 缓存清理接口要限制访问
location ~ /purge/ {
allow 127.0.0.1;
allow 10.0.0.0/8;
deny all;
# ...
}
# 3. 不要缓存包含用户信息的响应
# 如果后端在响应中包含用户信息,该接口不应该缓存
# 4. 隐藏后端错误信息
# 使用proxy_cache_use_stale时,后端错误不会暴露给用户
proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
4.2.3 性能调优
# 1. 使用sendfile提高静态文件传输效率
sendfile on;
tcp_nopush on;
tcp_nodelay on;
# 2. 开启aio(异步IO)
aio threads;
directio 4m; # 大于4MB的文件使用directio
# 3. 缓存文件打开句柄
open_file_cache max=10000 inactive=60s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
# 4. 调整共享内存大小
# keys_zone过小会导致无法存储足够的Key
# 1MB大约存储8000个Key
# 如果有100万URL需要缓存,至少需要125MB
# 5. 使用tmpfs作为热点缓存存储
# mount -t tmpfs -o size=4G tmpfs /var/cache/nginx/hot_cache
# 6. 缓存锁超时设置
proxy_cache_lock on;
proxy_cache_lock_timeout 5s; # 等待锁的超时
proxy_cache_lock_age 5s; # 锁的最大持有时间
五、故障排查和监控
5.1 故障排查
5.1.1 缓存不命中排查
# 步骤1:检查响应头
curl -I http://example.com/api/test
# 查看 X-Cache-Status
# 步骤2:检查是否有跳过缓存的条件
# 在配置中添加调试header
add_header X-Cache-Bypass $no_cache;
add_header X-Cache-Key $scheme$host$request_uri;
# 步骤3:检查后端响应头
curl -I http://backend:8080/api/test
# 看是否有 Cache-Control: no-store/no-cache/private
# 看是否有 Set-Cookie
# 步骤4:查看缓存文件是否生成
find /var/cache/nginx -name "*" -type f -mmin -5 | wc -l
# 如果为0,说明没有新文件生成
# 步骤5:检查错误日志
grep "cache" /var/log/nginx/error.log
5.1.2 缓存文件分析
# 查看缓存文件内容(包含响应头和body)
head -100 /var/cache/nginx/main_cache/a/bc/xxxxx
# 文件结构:
# - 元信息(Key, 创建时间, 过期时间等)
# - HTTP响应头
# - 空行
# - 响应Body
# 解析缓存文件的脚本
#!/bin/bash
# /opt/scripts/parse_cache.sh
CACHE_FILE=$1
echo"=== Cache File: $CACHE_FILE ==="
echo"=== Headers ==="
sed -n '/^KEY:/,/^$/p'$CACHE_FILE
echo"=== Response Headers ==="
sed -n '/^HTTP/,/^$/p'$CACHE_FILE
5.1.3 缓存状态统计
#!/bin/bash
# /opt/scripts/cache_stats.sh
# 从访问日志统计缓存命中率
LOG_FILE="/var/log/nginx/access.log"
echo"=== Cache Statistics ==="
# 统计各状态数量
echo"Status Counts:"
grep -oP 'cache:\K\w+'$LOG_FILE | sort | uniq -c | sort -rn
# 计算命中率
TOTAL=$(grep -c 'cache:'$LOG_FILE)
HIT=$(grep -c 'cache:HIT'$LOG_FILE)
RATE=$(echo"scale=2; $HIT * 100 / $TOTAL" | bc)
echo""
echo"Total Requests: $TOTAL"
echo"Cache Hits: $HIT"
echo"Hit Rate: $RATE%"
# 按URL统计MISS最多的
echo""
echo"Top 10 Cache MISS URLs:"
grep 'cache:MISS'$LOG_FILE | awk '{print $7}' | sort | uniq -c | sort -rn | head -10
5.2 性能监控
5.2.1 Prometheus监控指标
# 使用nginx-prometheus-exporter
# 或者自定义metrics
# 添加统计变量
log_format metrics '$upstream_cache_status $request_time $upstream_response_time';
# 使用mtail或其他工具解析日志生成metrics
# 关键指标:
# - nginx_cache_hit_total
# - nginx_cache_miss_total
# - nginx_cache_expired_total
# - nginx_cache_stale_total
# prometheus告警规则示例
groups:
-name:nginx_cache
rules:
-alert:NginxCacheHitRateLow
expr:|
(
sum(rate(nginx_cache_hit_total[5m])) /
sum(rate(nginx_cache_requests_total[5m]))
) < 0.7
for:10m
labels:
severity:warning
annotations:
summary:"Nginx cache hit rate is below 70%"
5.2.2 缓存磁盘监控
#!/bin/bash
# /opt/scripts/cache_disk_monitor.sh
CACHE_DIR="/var/cache/nginx"
THRESHOLD=80 # 使用率告警阈值
# 检查磁盘使用率
USAGE=$(df $CACHE_DIR | awk 'NR==2 {print $5}' | tr -d '%')
if [ $USAGE -gt $THRESHOLD ]; then
echo"[WARN] Cache disk usage: ${USAGE}%"
# 发送告警
fi
# 统计缓存文件数量
FILE_COUNT=$(find $CACHE_DIR -type f | wc -l)
echo"Cache files: $FILE_COUNT"
# 统计各目录大小
echo"Cache size by directory:"
du -sh $CACHE_DIR/*
5.2.3 实时监控脚本
#!/bin/bash
# /opt/scripts/cache_realtime.sh
# 实时显示缓存状态
whiletrue; do
clear
echo"=== Nginx Cache Realtime Monitor ==="
echo"Time: $(date)"
echo""
# 最近1分钟缓存状态
echo"Last 1 minute cache status:"
tail -1000 /var/log/nginx/access.log | \
grep -oP 'cache:\K\w+' | \
sort | uniq -c
echo""
# 缓存目录状态
echo"Cache directory status:"
du -sh /var/cache/nginx/* 2>/dev/null
echo""
# 当前连接数
echo"Current connections:"
curl -s http://127.0.0.1:8080/nginx_status 2>/dev/null || echo"Status page not available"
sleep 5
done
5.3 备份与恢复
5.3.1 缓存预热
#!/bin/bash
# /opt/scripts/cache_warmup.sh
# 缓存预热脚本
URL_FILE="/opt/scripts/warmup_urls.txt"
CONCURRENT=10
NGINX_HOST="http://localhost"
echo"Starting cache warmup..."
# 并发请求URL列表
cat $URL_FILE | xargs -P $CONCURRENT -I {} curl -s -o /dev/null -w "%{url_effective} -> %{http_code}\n""$NGINX_HOST{}"
echo"Cache warmup completed."
# 统计预热结果
echo"Warmup statistics:"
curl -I "$NGINX_HOST/api/test" 2>/dev/null | grep "X-Cache-Status"
# /opt/scripts/warmup_urls.txt
# 需要预热的URL列表
/
/hot
/category/1
/category/2
/api/public/config
/api/public/banner
5.3.2 缓存清理
#!/bin/bash
# /opt/scripts/cache_clean.sh
# 缓存清理脚本
CACHE_DIR="/var/cache/nginx"
case"$1"in
all)
# 清理所有缓存
rm -rf $CACHE_DIR/*
echo"All cache cleared."
;;
old)
# 清理7天前的缓存
find $CACHE_DIR -type f -mtime +7 -delete
echo"Old cache (>7 days) cleared."
;;
size)
# 清理到指定大小(保留最新的)
MAX_SIZE=${2:-10G}
# 使用du和find组合清理
while [ $(du -s $CACHE_DIR | awk '{print $1}') -gt $(numfmt --from=iec $MAX_SIZE) ]; do
# 删除最老的文件
find $CACHE_DIR -type f -printf'%T+ %p\n' | sort | head -1000 | awk '{print $2}' | xargs rm -f
done
echo"Cache cleaned to under $MAX_SIZE"
;;
*)
echo"Usage: $0 {all|old|size [MAX_SIZE]}"
exit 1
;;
esac
# 通知Nginx
nginx -s reload
5.3.3 缓存迁移
#!/bin/bash
# /opt/scripts/cache_migrate.sh
# 缓存迁移脚本(迁移到新服务器)
SOURCE_DIR="/var/cache/nginx"
TARGET_HOST="new-nginx-server"
TARGET_DIR="/var/cache/nginx"
# 使用rsync同步缓存文件
rsync -avz --progress $SOURCE_DIR/ $TARGET_HOST:$TARGET_DIR/
# 注意事项:
# 1. 缓存文件包含元信息,可能包含主机名,迁移后可能失效
# 2. 建议迁移后进行缓存预热而不是直接复制文件
# 3. 如果使用了proxy_cache_key包含$host,确保两台服务器域名一致
六、总结
6.1 技术要点回顾
Nginx proxy_cache的核心配置要素:
缓存区域定义(proxy_cache_path)
levels:目录层级,避免单目录文件过多keys_zone:共享内存区域,存储缓存Key索引max_size:磁盘缓存最大容量inactive:多久没访问就删除缓存Key设计(proxy_cache_key)
包含所有影响响应的因素 排除无关参数(如时间戳) 合理控制Key长度 缓存有效期(proxy_cache_valid)
根据内容类型设置不同过期时间 静态资源长缓存,动态内容短缓存 缓存更新策略
TTL过期自动更新 background_update后台更新 主动Purge清理 异常处理(proxy_cache_use_stale)
后端故障时返回旧缓存 保证服务可用性
6.2 进阶学习方向
分布式缓存
Redis/Memcached作为缓存后端 多台Nginx共享缓存 缓存一致性处理 边缘缓存
CDN配置和优化 多级缓存架构 缓存失效传播 动态内容缓存
ESI(Edge Side Includes) SSI(Server Side Includes) 片段缓存 缓存安全
缓存投毒攻击防护 敏感信息泄露防护 缓存穿透/击穿/雪崩
6.3 参考资料
Nginx官方文档 - ngx_http_proxy_module Nginx官方博客 - A Guide to Caching with NGINX HTTP Caching - MDN Web Docs RFC 7234 - HTTP Caching
附录
A. 命令速查表
nginx -t | |
nginx -T | |
nginx -s reload | |
curl -I URL | |
find /cache -type f | wc -l | |
du -sh /cache/* | |
rm -rf /cache/* | |
ab -n 1000 -c 50 URL |
B. 配置参数详解
proxy_cache_path | ||
proxy_cache | ||
proxy_cache_key | ||
proxy_cache_valid | ||
proxy_cache_min_uses | ||
proxy_cache_lock | ||
proxy_cache_lock_timeout | ||
proxy_cache_use_stale | ||
proxy_cache_background_update | ||
proxy_cache_revalidate | ||
proxy_cache_bypass | ||
proxy_no_cache | ||
proxy_ignore_headers |
C. 术语表
(版权归原作者所有,侵删)
免责声明:本文内容来源于网络,所载内容仅供参考。转载仅为学习和交流之目的,如无意中侵犯您的合法权益,请及时联系Docker中文社区!

温馨提示:文章内容系作者个人观点,不代表Docker中文对观点赞同或支持。
版权声明:本文为转载文章,来源于 互联网 ,版权归原作者所有,欢迎分享本文,转载请保留出处!

发表评论