千万级ip限流不可全局限制,应按活跃key数建模并分层聚合压缩:地域聚合、网段归并、身份优先、空key跳过;内存公式为zone_size(mb)=ceil(活跃key数÷16000)×1.25,需上线后监控使用率。

千万级 IP 不能直接用一个 limit_req_zone 全局限流,因为每个 IP 状态实际占用约 64 字节内存,硬算下来 1000 万 IP 就要近 640MB 共享内存——这既不经济,也不稳定。真正可行的做法是:先按业务真实活跃 key 数建模,再套公式反推内存,最后靠分层、聚合、跳过三招把总量压下来。
按活跃 key 数而非总 IP 数来估算
限流内存消耗只和「同时需要被记住的 key 数量」有关,不是日志里出现过的所有 IP。例如:
- 某核心登录接口,日活用户 200 万,但峰值并发调用的用户只有 50 万 → 活跃 key 数 ≈ 50 万
- CDN 回源流量集中在 12 个骨干节点 IP → 活跃 key 数 = 12(用
$http_x_real_ip+$server_name组合) - 海外请求按
$geoip2_country_code聚合,全球活跃国家约 80 个 → 活跃 key 数 ≈ 80
内存计算公式与推荐配置
公式为:zone_size(MB) = ceil(预估活跃 key 数 ÷ 16000) × 1.25(1.25 是 20%~30% 冗余系数)
- 50 万活跃用户 → ceil(500000 ÷ 16000) × 1.25 = 32 × 1.25 = 40 → 建议
zone=user_limit:40m - 若拆成 5 个区域 zone(如
user_cn、user_us、user_apac),每个只需 8–10m,更易调度且故障隔离 - 切忌写
zone=all_ips:10m:10MB 最多存 16 万个 key,连 2% 的活跃用户都覆盖不了
关键压缩手段:让千万 IP 映射到几百个逻辑 key
不记 IP,记它的“身份”或“归属”:
-
地域聚合:用
$geoip2_country_code或自定义 map 把 IP 归入国家/省份/运营商,10MB 可覆盖全部活跃区域 -
网段粗略归并:map 提取
$remote_addr前两段(如192.168),把数千 IP 合为一个 key -
身份优先:已登录用户用
$http_x_user_id;未登录时 fallback 到 IP 前缀,不全量记 IP -
空 key 跳过:CDN 回源、健康检查、内部调用等映射为
"",完全不占状态槽
上线后必须验证的三件事
配完不是结束,而是开始监控:
- 查
nginx -T | grep limit_req_zone确认配置已加载 - 看
curl http://127.0.0.1/nginx_status(需开启 stub_status)中 limit 相关计数是否合理增长 - 采集
shm_zone_XXX_used_size指标(通过 vts 或 OpenResty Prometheus 模块),使用率持续超 85%,立即扩容 zone










