如何设置proxy_cache_lock以应对高并发回源时防止源站请求崩溃?
- 内容介绍
- 文章标签
- 相关推荐
本文共计835个文字,预计阅读时间需要4分钟。
配置proxy_cache_lock防止高并发回源点击穿透,关键不是开了就行,而是让锁真正覆盖同一类请求,并确保它在缓存未命中(MISS)时能稳定地介入。它本身不防穿透、不抗雪崩,仅对同+key的瞬时MISS起作用——但这恰恰是源站崩掉时最常见的导火索。
必须先搭好缓存基础框架
没有缓存区,锁就无处落脚:
- 在
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)后续会被引用,大小按每 1MB 支持约 8000 个 key 估算;use_temp_path=off可避免临时文件拷贝,提升写入一致性。 - 确保磁盘路径存在且 Nginx 进程有读写权限(macOS/Linux 下尤其注意 SELinux 或目录 umask 限制)。
在 location 中精准启用并约束锁行为
锁只在 cache miss 时生效,且仅作用于完全一致的缓存 key:
- 启用缓存与锁:
proxy_cache my_cache;<br>proxy_cache_lock on;<br>proxy_cache_lock_timeout 5s;
超时建议设为 3–8 秒:太短,等待请求快速放弃锁并发回源;太长,用户明显卡顿,尤其后端响应慢时。 - 显式控制缓存 key,避免因 query 参数、header 差异导致锁失效:
默认 key 含$args,/api/user?id=1和/api/user?id=2就是两个独立锁。
若需统一锁定某类接口,可自定义:proxy_cache_key "$scheme$host:/api/user";
或剥离干扰项:proxy_cache_key "$scheme$host$request_uri";(忽略所有 query 参数) - 忽略无关响应头,防止缓存被跳过:
proxy_ignore_headers Set-Cookie Vary;
否则带Set-Cookie的响应默认不缓存,锁也形同虚设。
配合 stale 策略降低锁依赖强度
光靠锁等结果,不如让旧缓存“活”得更久一点:
- 启用 stale 回退:
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
当首个请求回源失败、超时或正在更新时,后续请求可直接返回旧缓存(stale),既减少等待,又避免全部降级失败。 - 延长热点资源有效期:
proxy_cache_valid 200 302 30s;<br>proxy_cache_valid 404 10s;
MISS 越少,锁竞争越弱;对 API 接口设 30 秒已足够缓解瞬时压力。
验证是否真实生效
别信配置,要看行为:
- 加响应头便于观测:
add_header X-Cache-Status $upstream_cache_status;
用curl -I查看:首次应为MISS,紧随其后的并发请求若返回HIT或UPDATING,说明锁已阻塞并复用结果。 - 压测验证后端访问量:
用ab -n 20 -c 10 http://your-site/api/hot并观察后端 access log —— 开启 lock 后,应只记录 1 条(或极少数)请求,而非 10 条。
本文共计835个文字,预计阅读时间需要4分钟。
配置proxy_cache_lock防止高并发回源点击穿透,关键不是开了就行,而是让锁真正覆盖同一类请求,并确保它在缓存未命中(MISS)时能稳定地介入。它本身不防穿透、不抗雪崩,仅对同+key的瞬时MISS起作用——但这恰恰是源站崩掉时最常见的导火索。
必须先搭好缓存基础框架
没有缓存区,锁就无处落脚:
- 在
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)后续会被引用,大小按每 1MB 支持约 8000 个 key 估算;use_temp_path=off可避免临时文件拷贝,提升写入一致性。 - 确保磁盘路径存在且 Nginx 进程有读写权限(macOS/Linux 下尤其注意 SELinux 或目录 umask 限制)。
在 location 中精准启用并约束锁行为
锁只在 cache miss 时生效,且仅作用于完全一致的缓存 key:
- 启用缓存与锁:
proxy_cache my_cache;<br>proxy_cache_lock on;<br>proxy_cache_lock_timeout 5s;
超时建议设为 3–8 秒:太短,等待请求快速放弃锁并发回源;太长,用户明显卡顿,尤其后端响应慢时。 - 显式控制缓存 key,避免因 query 参数、header 差异导致锁失效:
默认 key 含$args,/api/user?id=1和/api/user?id=2就是两个独立锁。
若需统一锁定某类接口,可自定义:proxy_cache_key "$scheme$host:/api/user";
或剥离干扰项:proxy_cache_key "$scheme$host$request_uri";(忽略所有 query 参数) - 忽略无关响应头,防止缓存被跳过:
proxy_ignore_headers Set-Cookie Vary;
否则带Set-Cookie的响应默认不缓存,锁也形同虚设。
配合 stale 策略降低锁依赖强度
光靠锁等结果,不如让旧缓存“活”得更久一点:
- 启用 stale 回退:
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
当首个请求回源失败、超时或正在更新时,后续请求可直接返回旧缓存(stale),既减少等待,又避免全部降级失败。 - 延长热点资源有效期:
proxy_cache_valid 200 302 30s;<br>proxy_cache_valid 404 10s;
MISS 越少,锁竞争越弱;对 API 接口设 30 秒已足够缓解瞬时压力。
验证是否真实生效
别信配置,要看行为:
- 加响应头便于观测:
add_header X-Cache-Status $upstream_cache_status;
用curl -I查看:首次应为MISS,紧随其后的并发请求若返回HIT或UPDATING,说明锁已阻塞并复用结果。 - 压测验证后端访问量:
用ab -n 20 -c 10 http://your-site/api/hot并观察后端 access log —— 开启 lock 后,应只记录 1 条(或极少数)请求,而非 10 条。

