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

八、结语

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

相关推荐
云烟成雨TD2 小时前
Spring AI 1.x 系列【25】结构化输出案例演示
java·人工智能·spring
大黄说说2 小时前
Go语言并发编程:Goroutine与Channel构建的CSP模型
java·后端·spring
0xDevNull2 小时前
Redis Lua 脚本详细教程
redis·缓存·lua
Flittly2 小时前
【SpringAIAlibaba新手村系列】(12)RAG 检索增强生成技术
java·人工智能·spring boot·spring·ai
MyY_DO2 小时前
缓存穿透-damai
缓存
中科三方3 小时前
域名NS记录修改全攻略:规则、误区、实操流程和常见问题
java·后端·spring
七夜zippoe3 小时前
设计模式在Spring等框架中的应用:模板方法、工厂、适配器等
java·spring·设计模式·模板·适配器·工厂
難釋懷3 小时前
Nginx本地缓存
nginx·spring·缓存