要实现Nginx缓存失效瞬间“零回源、秒开”,需协同启用proxy_cache_lock与proxy_cache_background_update:先配置共享缓存区并启用缓存,再通过lock控制首请求回源、background update后台静默刷新,配合proxy_cache_use_stale updating使后续请求立即返回过期缓存,最终达成用户无感、后端仅1次回源。

要让 Nginx 在缓存失效瞬间实现“零回源、秒开”,关键不是消灭所有回源,而是把用户可见的回源请求压到 0——即:用户不感知等待、不触发新回源、响应始终来自缓存(哪怕是过期的),同时后台悄悄刷新。这需要 proxy_cache_lock 和 proxy_cache_background_update 协同工作,并配以精准控制与容错兜底。
必须先搭稳缓存地基
没有缓存区,lock 和 background update 都是空谈:
- 在
http块中定义共享内存缓存区:proxy_cache_path /var/cache/nginx/proxy_cache levels=1:2 keys_zone=my_cache:256m inactive=1h use_temp_path=off;
注意:keys_zone名称(如my_cache)后续会被引用;use_temp_path=off避免临时文件拷贝,提升一致性;确保磁盘路径存在且 Nginx 有读写权限。 - 在目标
location中启用缓存:proxy_cache my_cache;
这是 lock 和 background update 生效的前提——没启用缓存,就不存在 MISS,自然不触发锁或后台更新。
用 proxy_cache_lock 控制首次回源节奏
它不防穿透,只管“同一 key 的瞬时未命中”——而这正是秒开网关最需守住的临界点:
- 开启锁并设合理超时:
proxy_cache_lock on;proxy_cache_lock_timeout 4s;
超时值建议设为后端 P95 响应时间的 1.2–1.5 倍(例如后端 P95 是 3.2s,这里设 4s)。太短会放行大量并发回源;太长则用户明显卡顿。 - 锁只对完全一致的 cache key 生效,务必统一 key:
proxy_cache_key "$scheme$host$request_uri";
忽略全部 query 参数(如?v=123、&utm_source=xxx),避免因 URL 差异导致锁失效。 - 忽略干扰响应头,防止缓存被跳过:
proxy_ignore_headers Set-Cookie Vary;
否则带Set-Cookie的响应默认不缓存,lock 就形同虚设。
靠 proxy_cache_background_update 实现“无感刷新”
它和 lock 是搭档,但职责不同:lock 让第一个请求去取新数据,background update 则让这个动作在后台静默完成,不阻塞任何用户请求:
- 启用后台更新:
proxy_cache_background_update on; - 配合
proxy_cache_use_stale updating,让所有等待中的请求立刻返回旧缓存:proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
关键是updating:只要缓存已存在(哪怕已过期),且后台正在刷新,Nginx 就直接返回旧内容,用户完全无感。 - 设置合理缓存有效期,降低 MISS 频次:
proxy_cache_valid 200 302 5m;
对接口类资源,5 分钟是较平衡的选择;静态资源可延长至 1h 或更久。
验证是否真达成“零回源秒开”
别信配置,要看行为:
- 加响应头观察状态:
add_header X-Cache-Status $upstream_cache_status;
并发请求同一路径时,应看到首个为MISS,其余全为HIT或STALE(非MISS),说明锁+stale+background update 共同生效。 - 检查后端 access log:
同一资源 URI 的请求频次应在缓存失效瞬间收敛为 1 次(首个回源)或极少量(仅后台更新线程),而非数十上百次并发打过去。 - 用
wrk -c 100 -t 4 "http://your-domain/path"压测未缓存路径,对比开启前后端请求数量——理想状态下,后端新增请求应 ≤ 2(1 次前台回源 + 1 次后台刷新)。


















