Nginx实现本地缓存查询

一、前言:什么是"本地缓存查询"?

在微服务架构中,我们经常遇到这样的场景:

  • 用户频繁查询商品详情(GET /api/product/123
  • 客户端轮询配置接口(GET /api/config/app
  • 第三方调用只读数据接口(如城市列表、字典项)

这些请求具有高读低写、结果稳定、重复率高的特点。

❌ 传统做法:每次请求都穿透到后端 → 数据库压力大、响应慢

Nginx 本地缓存查询 :将后端返回的 JSON 响应缓存在 Nginx 本地磁盘,后续相同查询直接返回缓存!

本文将教你如何用 Nginx 的 proxy_cache 模块,实现高效的本地缓存查询能力


二、核心机制:proxy_cache 如何工作?

💡 关键优势

  • 零代码改造:后端无需任何改动
  • 毫秒级响应:缓存命中时 RT < 1ms
  • 自动过期:按配置时间自动清理
  • 磁盘持久化:Nginx 重启后缓存仍有效(除非超时)

三、基础配置:5 步开启本地缓存查询

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

Lua 复制代码
http {
    # 定义用于查询缓存的区域
    proxy_cache_path /var/cache/nginx/query 
        levels=1:2                # 两级目录防 inode 耗尽
        keys_zone=query_cache:100m  # 共享内存区(100MB ≈ 80万 key)
        inactive=10m              # 10分钟未访问则删除
        max_size=2g               # 最大缓存 2GB
        use_temp_path=off;        # 关键!避免临时文件拷贝性能损耗

    # 创建目录并授权
    # mkdir -p /var/cache/nginx/query && chown nginx:nginx /var/cache/nginx/query
}

步骤 2:在查询接口启用缓存

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

    # 商品查询接口(只读、高频)
    location /api/product/ {
        # 启用缓存
        proxy_cache query_cache;
        
        # 自定义缓存 key(确保唯一性)
        proxy_cache_key "$host|$request_uri";
        
        # 仅缓存 200 成功响应,有效期 5 分钟
        proxy_cache_valid 200 5m;
        
        # 忽略后端 Cache-Control 头(由 Nginx 统一控制)
        proxy_ignore_headers Cache-Control Expires;
        
        # 透传真实 IP
        proxy_set_header X-Real-IP $remote_addr;
        proxy_pass http://product_service;
    }

    # 字典查询接口(几乎不变)
    location /api/dict/ {
        proxy_cache query_cache;
        proxy_cache_valid 200 1h;  # 缓存 1 小时
        proxy_pass http://dict_service;
    }
}

步骤 3:定义上游服务

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

upstream dict_service {
    server 10.0.0.20:8080;
}

四、高级技巧:精准控制缓存查询行为

4.1 添加缓存状态头(用于调试)

Lua 复制代码
# 在 location 中添加
add_header X-Cache-Status $upstream_cache_status always;

# 返回值说明:
# HIT    → 命中缓存
# MISS   → 未命中(已回源)
# BYPASS → 跳过缓存(如 POST 请求)

4.2 强制跳过缓存(调试用)

Lua 复制代码
# 请求带 ?debug=1 时不走缓存
if ($arg_debug = "1") {
    set $nocache "1";
}
proxy_cache_bypass $nocache;
proxy_no_cache $nocache;

4.3 防止缓存穿透(恶意查询)

Lua 复制代码
# 对不存在的 ID 返回 404 并缓存 1 分钟
proxy_cache_valid 404 1m;

# 或限制 ID 格式(正则匹配)
location ~ ^/api/product/(\d+)$ {
    proxy_cache query_cache;
    proxy_cache_valid 200 5m;
    proxy_pass http://product_service;
}

五、生产级最佳实践

5.1 缓存托底:后端挂了也能查

Lua 复制代码
location /api/campaign/ {
    proxy_cache query_cache;
    proxy_cache_valid 200 30s;
    
    # 关键!后端错误时使用过期缓存
    proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
    
    proxy_pass http://campaign_service;
}

效果 :即使后端宕机,用户仍能查看最近一次活动数据

5.2 性能优化建议

项目 推荐值 说明
存储介质 SSD 磁盘 避免 HDD I/O 瓶颈
inactive 5~30 分钟 根据数据更新频率调整
max_size ≤ 磁盘 80% 防止占满磁盘导致服务异常
keys_zone ≥ 50MB 高 QPS 场景需更大内存

5.3 清理缓存(手动刷新)

bash 复制代码
# 示例:清除商品 123 的缓存
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/query/$LEVEL1/$LEVEL2/$HASH
# 无需 reload,下次请求自动重建

六、验证缓存是否生效

6.1 通过响应头判断

bash 复制代码
curl -I "http://api.example.com/api/product/123"

首次请求

复制代码
HTTP/1.1 200 OK
X-Cache-Status: MISS
...

后续请求

复制代码
HTTP/1.1 200 OK
X-Cache-Status: HIT
...

6.2 查看缓存文件

bash 复制代码
# 查看缓存目录
ls /var/cache/nginx/query/a/bc/
# 输出:abcdef1234567890... (MD5 哈希值)

七、常见问题排查

问题 原因 解决方案
始终 MISS 后端返回 Cache-Control: no-cache 添加 proxy_ignore_headers Cache-Control;
缓存未过期 inactive 时间未到 检查 proxy_cache_validinactive 区别
磁盘空间不足 未设置 max_size 设置合理的 max_size 并监控磁盘
中文乱码 后端未指定 UTF-8 确保后端返回 Content-Type: application/json; charset=utf-8

八、结语

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

相关推荐
手握风云-25 分钟前
Spring AI:让大模型住进 Spring 生态(三)
java·后端·spring
Flying pigs~~9 小时前
RAG智慧问答项目
数据库·人工智能·缓存·微调·知识库·rag
许彰午10 小时前
CacheSQL(二):主从复制——OpLog 环形缓冲区与故障自动恢复
java·数据库·缓存
Jinkxs12 小时前
LoadBalancer- 主流负载均衡工具盘点:Nginx / Haproxy / Keepalived 基础介绍
运维·nginx·负载均衡
ReaF_star14 小时前
【安全】SSL证书更新操作手册(Nginx+Cloudflare+acme.sh)
nginx·安全·ssl
凯瑟琳.奥古斯特15 小时前
Redis是什么及核心特性
前端·css·redis·缓存
@#¥&~是乱码鱼啦16 小时前
Spring分层架构:Controller、Service、Mapper数据链路,IOC的真实工作意义
java·spring·架构
薪火铺子16 小时前
SpringMVC请求处理流程源码解析(第3篇):视图渲染与异常处理
java·后端·spring
云动课堂16 小时前
【运维实战】Nginx 高性能Web服务 · 一键自动化部署方案 (适配银河麒麟 V10 / openEuler / CentOS 7/8)
运维·前端·nginx
1.14(java)19 小时前
Spring AOP核心概念与实战指南
java·后端·spring