一、为什么我的缓存突然不工作了?

最近遇到一个挺有意思的问题:明明配置了Nginx反向代理缓存,但用户老是抱怨网站加载慢。一查日志,发现缓存根本没生效,所有请求都打到后端服务器去了。这就像你买了台新冰箱,结果发现它根本不制冷,食物全坏了——既浪费电又糟心。

这种情况通常有三大元凶:

  1. 缓存配置写错了(比如路径权限不对)
  2. 响应头设置有问题(比如后端强行禁用缓存)
  3. 缓存键设计不合理(比如每个请求都生成新key)

先看个典型错误配置示例(技术栈:Nginx 1.18 + Ubuntu 20.04):

proxy_cache_path /tmp/nginx_cache levels=1:2 keys_zone=my_cache:10m inactive=60m;

server {
    location / {
        proxy_cache my_cache;
        proxy_pass http://backend;
        
        # 错误1:没有设置缓存状态头
        add_header X-Cache-Status $upstream_cache_status;
        
        # 错误2:缓存key只用$uri,忽略查询参数
        proxy_cache_key "$uri";
    }
}

这个配置有两个致命问题:首先我们看不到缓存是否命中(缺少X-Cache-Status),其次商品详情页的?id=123和?id=456会被当作同一个页面缓存。就像图书馆把所有同名书归到同一书架,找书时肯定要乱套。

二、让缓存乖乖听话的秘诀

要让缓存正常工作,得掌握这几个核心配置:

1. 完整的缓存路径配置

proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=hot_cache:100m 
                 inactive=24h max_size=10g use_temp_path=off;
  • levels=1:2:创建三层子目录(防止单个目录文件过多)
  • max_size=10g:磁盘缓存上限(建议SSD分区)
  • use_temp_path=off:避免临时文件导致的性能损耗

2. 智能缓存键设计

proxy_cache_key "$scheme$request_method$host$request_uri$cookie_user";

包含协议、请求方法、域名、完整路径和用户cookie。就像超市储物柜,用购物小票上的条形码当钥匙,既不会拿错也不会重复。

3. 缓存过滤规则

proxy_cache_valid 200 302 10m;  # 成功页面缓存10分钟
proxy_cache_valid 404      1m;  # 404页面缓存1分钟
proxy_cache_valid any      5s;  # 其他状态码极短缓存

# 不缓存管理员后台
if ($request_uri ~* "^/admin") {
    set $do_not_cache 1;
}
proxy_cache_bypass $do_not_cache;

三、那些年我们踩过的坑

案例1:动态API被意外缓存

有个电商平台的商品价格API突然不更新了,查了半天发现是Nginx把GET请求全缓存了。解决方法是在location里添加:

# 只缓存静态资源
location ~* \.(jpg|css|js)$ {
    proxy_cache hot_cache;
    expires 7d;
}

# 不缓存API接口
location /api {
    proxy_pass http://backend;
    proxy_no_cache 1;  # 强制不缓存
}

案例2:Cookie导致缓存碎片化

用户登录后每个请求都带唯一sessionid,导致缓存命中率几乎为零。解决方案是清洗缓存key:

map $http_cookie $parsed_cookie {
    default "";
    "~*user_token=(?<token>[^;]+)" $token;
}

proxy_cache_key "$host$request_uri$parsed_cookie";

四、高级玩家必备技巧

1. 缓存预热策略

在服务器启动时自动加载热门内容:

# 预热脚本preheat.sh
URLS=("/hot-product" "/news" "/featured")
for url in "${URLS[@]}"; do
    curl -s -o /dev/null "http://localhost${url}"
done

2. 分层缓存策略

# 内存级热点缓存(存放访问频次最高的内容)
proxy_cache_path /dev/shm/micro_cache levels=1:2 keys_zone=micro:5m max_size=100m;

# 普通磁盘缓存
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=main:100m max_size=10g;

location / {
    # 先查内存缓存
    proxy_cache micro_cache;
    proxy_cache_valid 200 1m;
    
    # 内存未命中再查磁盘缓存
    error_page 404 = @fallback;
}

location @fallback {
    proxy_cache main;
    proxy_cache_valid 200 1h;
}

3. 缓存状态监控

location /cache-status {
    stub_status on;
    access_log off;
    allow 127.0.0.1;
    deny all;
}

配合Prometheus的nginx_exporter可以实时监控:

  • 缓存命中率
  • 缓存使用量
  • 过期项目数量

五、终极解决方案清单

当遇到缓存问题时,按照这个checklist排查:

  1. 检查磁盘空间 df -h /var/cache/nginx
  2. 验证目录权限 ls -ld /var/cache/nginx
  3. 查看响应头 curl -I http://example.com | grep Cache
  4. 检查错误日志 tail -f /var/log/nginx/error.log
  5. 强制刷新缓存 curl -X PURGE http://example.com/resource

记住,好的缓存策略应该像优秀的餐厅服务员——熟客来了直接上常点的菜,新客人则耐心询问需求。既提升效率又保持灵活性,这才是Nginx缓存配置的艺术。