对缓存接口并发管控需先构造唯一标识key(如$binary_remote_addr:$host$uri或归一化$cache_path),再用limit_conn_zone定义共享内存区,最后在对应location中用limit_conn绑定生效。

要对特定缓存接口做并发管控,关键不是只限 IP 或只限域名,而是把“缓存接口”这个业务语义映射成一个可识别、可复用的键(key),再通过 limit_conn_zone 定义共享内存区域,最后在对应 location 中用 limit_conn 绑定生效。
明确“缓存接口”的变量表达方式
所谓“缓存接口”,通常指具备以下特征的请求路径:以 /cache/、/api/v1/items 或带特定 query 参数(如 ?type=hot)的资源,且后端实际走的是 Redis/Memcached 等缓存层。Nginx 本身不感知业务缓存逻辑,所以需人工构造能唯一标识这类请求的变量:
- 若所有缓存接口统一前缀(推荐),可用
$uri截取,例如location ^~ /cache/ { ... }内部用$uri作为 key; - 若分散在不同路径但含共同参数(如
?cache=true),可用map指令提取:
map $arg_cache $cache_key {
"true" $binary_remote_addr; # 或更细粒度:$binary_remote_addr:$uri
default ""; }
limit_conn_zone $cache_key zone=cache_api:5m; - 避免直接用
$args,因参数顺序可能变化,导致同一接口被识别为多个 key; - 优先组合
$binary_remote_addr+ 接口标识(如$host$uri),兼顾客户端隔离与接口维度,例如:
limit_conn_zone "$binary_remote_addr:$host$uri" zone=perip_perapi:10m;
定义专用 zone 并控制内存用量
缓存接口往往高频、低延迟,连接生命周期短,但并发易突增。因此 zone 大小需按预期并发量预估:
- 每个 key 占约 32 字节(含连接计数、锁等元信息),10MB zone 可存约 32 万个独立 key;
- 若只限制“每接口每 IP 最多 3 连接”,且预计最多 100 个活跃缓存接口、1 万 IP,则
zone=cache_api:2m已足够; - 若按
$host$uri单独限流(不带 IP),需警惕 URI 带动态 ID(如/item/123)导致 key 爆炸,此时应先用map归一化路径:
map $uri $cache_path {
"~^/item/[0-9]+$" "/item/{id}";
"~^/user/[0-9]+$" "/user/{id}";
default $uri;
}
limit_conn_zone $cache_path zone=cache_route:5m;
在 location 中精准启用并协同防护
不能全局写 limit_conn,必须落在真正走缓存的 location 块内,且建议叠加基础防护措施:
- 仅对明确标记为缓存的 location 启用,例如:
location ~ ^/(cache|api/v1/(items|tags)) {
limit_conn cache_route 5;
limit_conn_log_level warn;
limit_conn_status 429;
} - 配合
limit_rate防止被限流连接持续占带宽,例如limit_rate 100k; - 若该 location 同时有非缓存逻辑(如 fallback 到 DB),建议拆分为子 location 或用
try_files分离路径,确保限流只作用于纯缓存分支; - 开启 access log 记录限流详情:
log_format limit_log '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" $limit_key $limit;'
access_log logs/cache_access.log limit_log;
验证与可观测性要点
配置生效后,需确认是否真按预期维度限流,而非误伤:
- 用
curl -v http://host/cache/item多开几个终端并发请求,观察是否在第 6 次(假设设为 5)返回 429; - 检查 error log 中是否有
limiting connections by zone日志,并核对$limit_key是否匹配你定义的变量值(如/cache/item); - 用
nginx -t确保语法正确,特别注意map块必须在http块顶层,且limit_conn_zone的 key 必须是已声明变量; - 不建议与
limit_req混用在同一 location——二者触发条件不同(连接建立 vs 请求到达),容易造成策略冲突或日志混淆。

















