一、前言:为什么 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 |
八、结语
感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!