通过map指令构建语义化变量作为limit_req_zone的$key,可实现按业务场景(如VIP/普通用户、导出接口、异常登录)精准限流;需权衡key粒度与内存占用,避免直接使用$request_uri等高熵变量。

直接用 limit_req_zone 配合自定义变量,就能跳出“只按 IP 限流”的局限,把流量控制精准锚定到真实业务场景里——比如区分 VIP 用户和普通用户、限制导出类接口频次、拦截异常登录行为等。
核心思路:用 map 构建动态 key
Nginx 本身不支持直接从请求体或复杂逻辑中提取变量,但可以通过 map 指令,基于已有输入(如 header、cookie、uri 参数)映射出可读性强、语义明确的自定义标识。这个标识就是 limit_req_zone 的 $key。
- 先在
http块顶部定义map,例如识别高风险路径:
map $request_uri $is_export {
~^/api/v1/export 1;
default 0;
}
- 再用该变量做限流维度:
limit_req_zone $is_export zone=export_limit:5m rate=2r/m;
这样只有访问导出接口的请求才会被计入该 zone,其他请求完全不受影响。
按用户身份分级限流
若后端已透传用户等级(如通过 X-User-Rank header),可直接分层建 zone:
- 定义两个 zone,分别对应不同速率:
limit_req_zone $http_x_user_rank zone=rank_limit:10m rate=5r/s;
limit_req_zone $http_x_user_id zone=user_limit:20m rate=1r/s;
- 在 location 中组合使用:
对付费用户(X-User-Rank: premium)走宽松策略,对未登录用户(X-User-Rank: guest)走严格策略;
同时用user_limit对单个用户 ID 兜底,防刷号。
结合业务状态做条件限流
限流不是一成不变的,要能响应实时业务信号。例如:当某用户最近 1 分钟内连续触发 3 次 401,临时降为最低配额。
- 借助 OpenResty 的
resty.limit.req可实现动态 key + 运行时判断; - 纯 Nginx 场景下,可用
map+ 状态上报机制间接实现:
前端或网关在检测到异常后,写入一个带时间戳的 cookie(如abnormal=1678901234),
再用map判断该 cookie 是否存在且未过期,生成特殊 key(如abnormal_1678901234),
最后用独立 zone 对其限速:limit_req_zone $abnormal_key zone=abnormal_limit:2m rate=0.1r/s;
内存与粒度的平衡要点
自定义 key 越精细,内存占用越高,需按实际规模预估:
-
$binary_remote_addr:IPv4 固定 4 字节,1MB ≈ 1.6 万个 IP; - 字符串类 key(如
$http_x_user_id):长度不可控,建议配合limit_req_zone的 size 参数预留余量; - 避免用
$request_uri直接做 key(参数多、变化大),优先提取固定路径段或哈希后截取; - 多个 zone 可共存,但每个都占独立内存,上线前用
nginx -t校验配置,并观察shared memory使用率。










