proxy_cache_lock 通过串行化同一缓存 key 的并发未命中请求来缓解缓存击穿,需系统配置锁得准(统一 cache key)、锁得住(启用缓存区与 lock)、退得快(use_stale + background_update)、源头少(减少 miss)。

proxy_cache_lock 本身不“防止”缓存击穿,它只对同一缓存 key 的并发未命中(MISS)请求做串行化:放行第一个回源,其余等待结果写入后直接读缓存。要让它在真实场景中稳住后端,必须围绕四个关键点系统配置——锁得准、锁得住、退得快、源头少。
锁得准:所有请求必须落在同一个 cache key 上
锁按 key 绑定,key 不一致就等于没锁。默认 $request_uri 包含 query 参数,/api/hot?id=1 和 /api/hot?id=2 就是两个独立 key,数万请求会触发数万次回源。
- 对固定路径热点接口(如商品详情),统一 key:
proxy_cache_key "$scheme$host:/api/product"; - 更通用做法是剥离 query 参数:
proxy_cache_key "$scheme$host$uri";(丢掉 $args) - 过滤前端随机参数(
?t=1716942840、?v=2.4.1)和易变 header(Authorization、User-Agent、Cookie) - 配合
proxy_ignore_headers Set-Cookie Vary;,避免响应因含 Set-Cookie 被跳过缓存
锁得住:三要素缺一不可
没有缓存区、没启用缓存、location 里没开 lock,机制完全不触发。
FastAPI + Flask 混合部署最佳实践,解决路由定义、API 代理等常见问题,适用于同时运行 FastAPI API 与 Flask 前端的场景。
- 在 http 块定义缓存区:
proxy_cache_path /var/cache/nginx/proxy_cache levels=1:2 keys_zone=my_cache:512m inactive=3h use_temp_path=off;
—— keys_zone=my_cache:512m 是核心,512MB 内存可支撑约 400 万个 key - 确保目录存在且 Nginx 进程有读写权限:
mkdir -p /var/cache/nginx/proxy_cache && chown www:www /var/cache/nginx/proxy_cache - 在目标 location 中必须启用缓存:
proxy_cache my_cache;
没这句,就没有 MISS,lock 就是摆设 - 在同一 location 中开启 lock:
proxy_cache_lock on;<br>proxy_cache_lock_timeout 5s;
超时建议 3–8 秒:太短易放弃,太长用户卡顿
退得快:stale 是保命配置
首个请求若慢、失败或超时,不能让其余请求干等或全部穿透。
- 允许返回旧缓存(即使已过期):
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504; - 可选后台静默更新:
proxy_cache_background_update on; - 对空响应也缓存,防穿透:
proxy_cache_valid 404 10s;
源头少:减少 MISS 才是治本
MISS 越少,锁竞争越弱,系统压力越小。
- 延长热点响应有效期:
proxy_cache_valid 200 302 30s;(API)proxy_cache_valid 200 1h;(静态资源) - 避免误配
proxy_no_cache或proxy_cache_bypass - 检查上游响应头是否含
Cache-Control: no-cache、private或no-store,这些会绕过缓存 - 用
add_header X-Cache-Status $upstream_cache_status;配合压测验证行为:看到大量 MISS 后紧跟 HIT,且并发请求日志时间戳高度集中,说明 lock 起作用










