霸王餐API网关层缓存:Nginx Proxy Cache与Cache-Control细节

霸王餐API网关层缓存:Nginx Proxy Cache与Cache-Control细节

缓存架构设计目标

"吃喝不愁"App的霸王餐活动接口(如 /api/v1/campaigns/{id})具有高读低写、内容时效性要求适中的特点(数据变更后允许5秒内延迟)。为减轻后端服务压力,我们在 Nginx 网关层部署 proxy_cache,结合后端返回的 Cache-Control 头实现智能缓存策略。

Nginx Proxy Cache 基础配置

nginx 复制代码
http {
    proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=campaign_cache:10m max_size=2g inactive=60m use_temp_path=off;

    server {
        listen 80;
        server_name api.eatfree.juwatech.cn;

        location /api/v1/campaigns/ {
            proxy_cache campaign_cache;
            proxy_cache_key "$scheme$request_method$host$request_uri";
            proxy_cache_valid 200 5s;
            proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
            proxy_cache_background_update on;
            proxy_cache_lock on;

            proxy_pass http://backend-service;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;

            add_header X-Cache-Status $upstream_cache_status;
        }
    }
}

关键参数说明:

  • keys_zone=campaign_cache:10m:分配10MB内存存储缓存键(约可存8万条);
  • inactive=60m:60分钟未被访问则自动清理;
  • proxy_cache_valid 200 5s:仅对状态码200缓存5秒;
  • proxy_cache_background_update on:缓存过期时后台更新,避免请求堆积;
  • add_header X-Cache-Status:用于调试(HIT/MISS/BYPASS)。

后端响应头控制(Java示例)

在 juwatech.cn.controller.CampaignController 中精确控制缓存行为:

java 复制代码
package juwatech.cn.controller;

import org.springframework.http.CacheControl;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

@RestController
public class CampaignController {

    @GetMapping("/api/v1/campaigns/{id}")
    public ResponseEntity<CampaignDetail> getCampaign(@PathVariable String id) {
        CampaignDetail detail = fetchFromService(id);
        if (detail == null || detail.isExpired()) {
            // 不可缓存的响应
            return ResponseEntity.noContent().build();
        }

        // 公开缓存,最大5秒,必须重新验证
        CacheControl cc = CacheControl.maxAge(5, TimeUnit.SECONDS)
            .mustRevalidate()
            .cachePublic();

        return ResponseEntity.ok()
            .cacheControl(cc)
            .header("Vary", "Accept-Encoding")
            .body(detail);
    }

    private CampaignDetail fetchFromService(String id) {
        // 模拟DB或RPC调用
        return new CampaignDetail(id, "霸王餐第" + id + "期", false);
    }
}

生成的响应头:

复制代码
HTTP/1.1 200 OK
Cache-Control: max-age=5, must-revalidate, public
Vary: Accept-Encoding

Nginx 与 Cache-Control 的交互规则

Nginx 默认不 完全遵循 Cache-Control,需显式启用:

nginx 复制代码
location /api/v1/campaigns/ {
    proxy_cache campaign_cache;
    proxy_ignore_headers Cache-Control Expires; # ❌ 错误!会忽略后端控制
}

正确做法是保留 后端头,并配合 proxy_cache_valid 作为兜底:

nginx 复制代码
# 不设置 proxy_ignore_headers
proxy_cache_valid 200 10s; # 仅当后端未返回 Cache-Control 时生效

若后端返回 Cache-Control: max-age=5,Nginx 将优先使用该值,覆盖 proxy_cache_valid。

绕过缓存的场景处理

运营人员需立即看到变更,可通过带特殊Header绕过缓存:

nginx 复制代码
location /api/v1/campaigns/ {
    set $nocache "";
    if ($http_x_admin_bypass = "true") {
        set $nocache "true";
    }
    proxy_cache_bypass $nocache;
    proxy_no_cache $nocache;

    # ... 其他配置
}

前端调用时添加:

http 复制代码
GET /api/v1/campaigns/123 HTTP/1.1
X-Admin-Bypass: true

此时 Nginx 直接回源,且不缓存该响应。

缓存键精细化设计

默认 $request_uri 包含查询参数,但某些参数不应影响缓存(如 ?utm_source=xxx):

nginx 复制代码
map $request_uri $cache_uri {
    default $request_uri;
    ~^(?P<path>/api/v1/campaigns/\d+)(\?.*)?$ $path;
}

server {
    location /api/v1/campaigns/ {
        proxy_cache_key "$scheme$request_method$host$cache_uri";
        # ...
    }
}

确保 /api/v1/campaigns/123?debug=true 与 /api/v1/campaigns/123 共享同一缓存。

验证与监控

  • 查看缓存状态:curl -I https://api.eatfree.juwatech.cn/api/v1/campaigns/123

    复制代码
    X-Cache-Status: HIT
  • 检查磁盘缓存:ls /var/cache/nginx/

  • 日志记录缓存命中:

    nginx 复制代码
    log_format cache '$remote_addr - $upstream_cache_status [$time_local] '
                     '"$request" $status $body_bytes_sent';
    access_log /var/log/nginx/cache.log cache;

注意事项

  • 缓存时间不宜过长,霸王餐数据变更频繁;
  • 敏感接口(如含用户ID)禁止缓存;
  • 使用 Vary 头区分不同客户端(如 Accept-Encoding);
  • 定期清理磁盘缓存目录,防止 inode 耗尽。

本文著作权归吃喝不愁app开发者团队,转载请注明出处!

相关推荐
桃西西呀3 分钟前
Spring AI Alibaba 之七:我没写一行 tracing 埋点,Agent 每一步却被 Micrometer 看得清清楚楚
人工智能·spring·llm
桃西西呀4 分钟前
Spring AI Alibaba 之八:我让 Agent 直接执行 shell 命令,它却读到了目录里的密钥,沙箱到底防住了什么
人工智能·spring·llm
李纲明4 分钟前
WordPress 站点变慢:按 TTFB → 缓存 → 查询 → 前端 分层排查(含配置注意)
前端·缓存·性能优化·wordpress·后端开发
我不会插花弄玉16 分钟前
4.string类型【由浅入深-redis】
数据库·redis·缓存
Riwuarua1 小时前
从近似0基础开始FPGA开发——Part.23:AXI/AXIS 数据搬运、DMA 与 DDR 缓存架构设计
缓存·fpga开发
~光~~2 小时前
【嵌入式linux学习】Cache 策略:Write-Through / Write-Back + Allocation
linux·学习·spring
m0_587383002 小时前
24 小时自助健身房系统软件开发实战指南与案例解析
java·spring boot·spring·系统架构·需求分析
m0_587383004 小时前
工业场景设备维修维护实战技巧 全流程标准化落地与常见问题排查指南
java·spring·小程序·架构·需求分析
木头科技4 小时前
【AI 工程化第八篇】Spring AI 多模型路由实战:DeepSeek、通义、Kimi、OpenAI 如何统一接入和自动切换
java·人工智能·spring
我是人✓5 小时前
Spring IOC注解全解析和Spring整合测试单元
java·后端·spring