Nginx本地缓存API

一、前言:为什么 API 也需要 Nginx 本地缓存?

你是否面临这些 API 性能瓶颈?

  • ❌ 商品详情页接口 QPS 高达 10w+,后端扛不住
  • ❌ 用户配置接口(低频变更)被频繁调用
  • ❌ 后端服务偶发超时,导致用户体验卡顿
  • ❌ 活动接口在大促时直接被打垮

Nginx 本地缓存(proxy_cache) 是官方提供的服务端缓存机制 ,专为 API 设计:

将 JSON 响应缓存到本地磁盘

相同请求直接返回缓存,绕过后端

实现"缓存托底"------后端挂了也能返回旧数据

本文将手把手教你为 API 接口配置 Nginx 本地缓存 ,并提供生产级最佳实践


二、核心原理:proxy_cache 如何缓存 API?

💡 关键点

  • 缓存存储在本地磁盘(可配置内存)
  • 默认缓存键:$scheme$proxy_host$request_uri
  • 支持按状态码(200/404)控制缓存策略

三、基础配置:5 步开启 API 缓存

步骤 1:定义缓存区域(http 块)

Lua 复制代码
http {
    # 定义 API 缓存区域
    proxy_cache_path /var/cache/nginx/api 
        levels=1:2                # 目录层级(防单目录文件过多)
        keys_zone=api_cache:100m  # 共享内存区(100MB ≈ 80万 key)
        inactive=10m              # 10分钟未访问则删除
        max_size=5g               # 最大缓存 5GB
        use_temp_path=off;        # 关键!避免临时文件拷贝

    # 创建目录
    # mkdir -p /var/cache/nginx/api && chown nginx:nginx /var/cache/nginx/api
}

步骤 2:在 API 路径启用缓存

Lua 复制代码
server {
    listen 80;
    server_name api.example.com;

    # 商品详情接口(高频读、低频写)
    location /api/product/ {
        proxy_cache api_cache;
        proxy_cache_key "$host|$request_uri";  # 自定义 key
        
        # 仅缓存 200 响应,有效期 5 分钟
        proxy_cache_valid 200 5m;
        
        # 忽略后端 Cache-Control 头(强制由 Nginx 控制)
        proxy_ignore_headers Cache-Control Expires Set-Cookie;
        
        # 透传真实 IP
        proxy_set_header X-Real-IP $remote_addr;
        proxy_pass http://product_backend;
    }

    # 用户配置接口(几乎不变)
    location /api/user/config/ {
        proxy_cache api_cache;
        proxy_cache_valid 200 1h;  # 缓存 1 小时
        proxy_pass http://user_backend;
    }
}

步骤 3:定义上游服务

Lua 复制代码
upstream product_backend {
    server 10.0.0.10:8080;
    server 10.0.0.11:8080;
}

upstream user_backend {
    server 10.0.0.20:8080;
}

四、高级配置:精准控制 API 缓存行为

4.1 缓存状态透传(用于监控)

Lua 复制代码
# 添加缓存状态头
add_header X-Cache-Status $upstream_cache_status always;

# 可能的值:
# - MISS:未命中
# - HIT:命中
# - EXPIRED:过期(正在后台更新)
# - BYPASS:跳过缓存(如 POST 请求)

4.2 跳过缓存(调试或写操作)

Lua 复制代码
# POST/PUT/DELETE 不缓存
if ($request_method ~* ^(POST|PUT|DELETE)$) {
    set $nocache "1";
}

# 请求带 ?nocache=1 时不走缓存
if ($arg_nocache = "1") {
    set $nocache "1";
}

proxy_cache_bypass $nocache;
proxy_no_cache $nocache;

4.3 按用户隔离缓存(个性化 API)

Lua 复制代码
# 为登录用户缓存个性化内容
proxy_cache_key "$host|$request_uri|$cookie_user_id";

# 或从 Token 中提取用户 ID(需 OpenResty)
# proxy_cache_key "$host|$request_uri|$jwt_claim_user_id";

五、生产级最佳实践:API 专属优化

5.1 缓存托底(后端宕机时返回旧数据)

Lua 复制代码
location /api/campaign/ {
    proxy_cache api_cache;
    proxy_cache_valid 200 30s;
    
    # 关键!后端错误时使用过期缓存
    proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
    
    # 后台更新缓存(避免请求堆积)
    proxy_cache_background_update on;
    
    proxy_pass http://campaign_backend;
}

效果

  • 后端宕机 → 用户仍能看到最近一次活动数据
  • 大促期间服务 SLA 从 95% 提升至 99.95%

5.2 性能优化建议

项目 推荐值 说明
缓存目录 SSD 磁盘 避免 HDD I/O 瓶颈
inactive ≥ 业务更新周期 商品详情设 5-10 分钟
max_size ≤ 磁盘 80% 防止占满磁盘
keys_zone 100MB 起 每 1MB ≈ 8000 个 key

5.3 清理缓存(Purging)

Nginx 开源版不支持 PURGE,可通过脚本清理

Lua 复制代码
# 根据 URL 计算缓存 key 的哈希(需与 proxy_cache_key 一致)
KEY="api.example.com|/api/product/123"
HASH=$(echo -n "$KEY" | openssl md5 | cut -d' ' -f2)

# 删除缓存文件
LEVEL1=${HASH: -1}
LEVEL2=${HASH: -3:2}
rm -f /var/cache/nginx/api/$LEVEL1/$LEVEL2/$HASH

# 重载 Nginx(非必须,但推荐)
nginx -s reload

💡 企业方案 :使用 Nginx Plus 的 proxy_cache_purge 指令。


六、验证与监控

6.1 检查缓存是否生效

Lua 复制代码
curl -I http://api.example.com/api/product/123
# 查看响应头
# X-Cache-Status: HIT

6.2 监控缓存指标

Lua 复制代码
# 查看缓存目录大小
du -sh /var/cache/nginx/api

# 日志记录缓存状态
log_format api_cache '$remote_addr - $upstream_cache_status [$time_local] '
                     '"$request" $status $body_bytes_sent';
access_log /var/log/nginx/api_cache.log api_cache;

七、常见问题排查

问题 原因 解决
缓存未生效 后端返回 Cache-Control: no-cache 添加 proxy_ignore_headers Cache-Control;
缓存穿透 大量唯一 ID(如 /api/user/随机字符串) 规范 API 设计,或返回 404
磁盘写满 max_size 未设置 设置合理的 max_size
中文乱码 编码不一致 确保后端返回 UTF-8

八、结语

感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!

相关推荐
二哈赛车手7 小时前
新人笔记---ApiFox的一些常见使用出错
java·笔记·spring
栗子~~7 小时前
JAVA - 二层缓存设计(本地缓冲+redis缓冲+广播所有本地缓冲失效) demo
java·redis·缓存
隔窗听雨眠8 小时前
多活部署、CDN加速与边缘缓存全链路优化实战
缓存
未若君雅裁9 小时前
MyBatis 一级缓存、二级缓存与清理机制
java·缓存·mybatis
阿维的博客日记10 小时前
Nacos 为什么能让配置动态生效?(涉及 @RefreshScope 注解)
java·spring
1892280486111 小时前
NY352固态MT29F32T08GWLBHD6-24QJ:B
大数据·服务器·人工智能·科技·缓存
丷丩12 小时前
三级缓存下MVT地图瓦片服务性能优化策略
算法·缓存·性能优化·gis·geoai-up
柿柿快乐13 小时前
Redis 入门第一课:全局命令、内部编码与单线程模型
redis·学习·缓存·基础教学
周杰伦的稻香13 小时前
Ollama访问限制
nginx·ai
磊 子13 小时前
1.4CPU缓存一致性
java·spring cloud·缓存·系统