限流与缓存叠加故障主因是行为逻辑干扰而非模块冲突:一、限流响应(429/503)被误缓存,需用proxy_no_cache $limit_req_status规避;二、限流与缓存key维度不一致导致共享错误,应统一身份标识;三、缓存未命中时并发回源触发重复限流,可启用proxy_cache_lock并调整限流粒度;四、多层代理下头部叠加干扰,需隐藏上游限流头并统一缓存控制。

限流和缓存叠加时出问题,往往不是“模块打架”,而是行为逻辑互相干扰:限流在请求入口拦截,缓存则在响应阶段介入;若两者对同一请求的判定维度不一致(比如限流看 IP,缓存却忽略 IP),就容易出现“该限没限、该缓没缓、甚至缓存了被限流返回的 429 页面”这类反直觉故障。排查关键在于拆开看链路,而不是盯着模块本身。
一、确认限流是否误缓存了拒绝响应
这是最隐蔽也最常发生的冲突——Nginx 把限流触发的 429/503 响应也存进了缓存,后续相同请求直接命中缓存,返回错误码,看起来像“限流永远生效”。
- 用 curl -I 请求一个已知会触发限流的接口(如连续快速发 3 次),观察响应头中是否有 X-Cache-Status: HIT,同时状态码是 429
- 检查缓存配置中是否漏加 proxy_cache_bypass 和 proxy_no_cache:必须让限流响应绕过缓存,例如:
location /api/ {
limit_req zone=api burst=5 nodelay;
proxy_cache my_cache;
proxy_no_cache $limit_req_status;
proxy_cache_bypass $limit_req_status;
} - 注意:$limit_req_status 是 Nginx limit_req 模块内置变量,值为 “PASSED” 或 “REJECTED”,只要不是空,就代表该请求被限流处理过
二、检查限流与缓存的 key 维度是否矛盾
限流按 IP 或 token 控制,缓存却按 URI + Host 缓存,会导致“不同用户共用一个缓存页,但其中一人被限流后,其他人也看到 429”。
- 构造两个请求:仅 Cookie 或 Authorization 不同,其余参数(URI、Host、Accept)完全一致,用 sha256sum 对比响应体哈希;若哈希不同,说明响应本应差异化,但当前缓存 key 没包含身份字段
- 对应修正 proxy_cache_key:若接口需用户隔离,不能只写 $scheme$host$request_uri,而要加入身份标识,例如:
proxy_cache_key "$scheme$host$request_uri $cookie_token";
或解析 JWT 后取 sub 字段做哈希(需配合 lua 模块) - 同时确保限流 zone 的定义维度与缓存 key 中的身份维度一致,避免“按 IP 限流,却按 token 缓存”这种错位
三、验证限流是否在缓存未命中时重复触发
当缓存失效、多个并发请求同时回源,限流模块可能对每个请求单独计数,导致瞬时超限(比如 burst=10,但 12 个并发请求一起打进来,前 10 个通过,后 2 个被拒),而实际业务只希望“每秒最多处理 10 次回源”。
- 启用 proxy_cache_lock on;:它会让非首请求等待首个回源完成后再读缓存,天然减少并发回源数量,间接缓解限流压力
- 把限流策略从“每秒请求数”调整为“每秒后端调用数”,可通过自定义变量实现,例如:
set $backend_key "$host$request_uri";
limit_req zone=backend burst=10 nodelay;
再配合 proxy_cache_lock,就能控制真正打到后端的流量峰值 - 观察 error.log 中是否密集出现 limiting requests 日志,且时间戳高度集中,这是并发回源触发限流的典型信号
四、留意多层代理下限流与缓存的头部叠加干扰
如果 Nginx 前面还有 CDN 或另一层 Nginx,它们各自加了限流和缓存头(如 Cache-Control、X-RateLimit-Limit),客户端看到的是混合结果,可能误判限流状态或缓存失效时机。
- 用 curl -I 查看完整响应头,重点比对:
— X-RateLimit-Limit / X-RateLimit-Remaining 是否来自你配置的 Nginx 层
— Cache-Control 是否出现多个值(如 no-cache, public, max-age=3600),说明多层 add_header 叠加 - 在限流生效的 location 块内,显式清除上游可能注入的限流头:
proxy_hide_header X-RateLimit-Limit;
proxy_hide_header X-RateLimit-Remaining; - 对缓存控制头,避免多层都设 Cache-Control;建议统一由最靠近后端的 Nginx 控制,外层用 proxy_ignore_headers Cache-Control; 忽略上游值











