limit_req_zone 不适用于百万级静态并发的ip精确限流,因内存开销大、状态易淘汰导致限速失效;可行方案是聚合key(如地域、cdn角色)、分层zone+白名单跳过,并通过error.log、rss、limit_status日志验证实效性。

直接说结论:limit_req_zone 本身不适用于支撑“百万级静态并发”的 IP 精确限流,因为内存开销不可持续——100 万个活跃 IP 至少需约 64MB 共享内存,而“静态并发”意味着这些 IP 在限速窗口内长期驻留,极易填满 zone 并触发状态淘汰,导致限速失效。真正可行的路径是绕过全量 IP 存储,用聚合、分层与跳过策略压缩有效状态数。
明确“百万级静态并发”的真实含义
所谓“静态并发”,通常指在限速时间窗口(如 1 秒或 1 分钟)内,有近百万个不同 IP 同时发起请求。但现实中:
- 极少业务真有百万个独立、高频、且需 individually 限流的 IP;更多是 CDN 节点、爬虫集群、运营商 NAT 网关后的真实用户集中出口
- 若真按 $binary_remote_addr 为 key 存百万个状态,单 zone 至少要 64MB 内存,且哈希冲突上升、查询延迟增加,worker 进程 RSS 明显上涨
- Nginx 共享内存区不是数据库,它不保证 key 永久存在;超出容量后会淘汰旧记录,造成“限速漂移”——部分 IP 突然不被限制
用聚合 key 替代单 IP,把百万降为百量级
核心思路:不记“谁来了”,而记“哪类流量来了”。例如:
- 按地理区域聚合:用
$geoip_country_code或自定义 map 将 IP 归属到国家/省份/AS 号,key 改为$country_code。全球国家数<250,10MB zone 即可覆盖全部 - 按网络角色聚合:通过
map指令将 CDN 回源 IP(如 Cloudflare、阿里云全站加速)、监控探针、内部调用来源映射为统一标识,如key $cdn_role,再对cdn_role=cf设限 - 按 User-Agent 特征聚类:对高频爬虫 UA(如 AhrefsBot、DotBot)单独提取字段,key 设为
$bad_ua,避免为每个爬虫 IP 单独占槽
分层 zone + 白名单跳过,精准复用内存
把有限内存分配给真正需要控制的流量维度:
-
全局兜底 zone:如
zone=global_flood:2m rate=500r/s,key 用$server_name,防整个域名被刷垮,2MB 足够 -
重点路径 zone:只在
/login、/api/submit等敏感接口启用limit_req zone=strict_api:5m,key 可组合$binary_remote_addr$http_user_agent防 UA 轮换,5MB 支持约 8 万高风险组合 -
白名单彻底跳过:用
map将可信 IP 段(如公司办公网、K8s Service CIDR、CDN 回源段)映射为空 key:map $binary_remote_addr $limit_key {<br> default $binary_remote_addr;<br> 192.168.0.0/16 "";<br> 104.16.0.0/12 "";<br>}
这样白名单 IP 完全不写入任何 zone,零内存消耗
验证是否真撑住了,别只看配置生效
上线后必须检查三项实际指标:
- 查 error.log 是否频繁出现
limiting requests, excess:且对应 IP 状态几秒内消失——这是内存不足、状态被挤掉的典型信号 - 用
ps aux | grep nginx观察 worker 进程 RSS 内存是否异常增长(如单进程超 500MB),可能因 zone 过大或哈希冲突加剧 - 开启限流日志:
log_format limitlog '$remote_addr - $status [$time_local] "$request" $limit_status';,观察$limit_status中hit和passed的比例是否符合预期,大量-(未匹配任何 zone)说明 key 设计或 map 映射有漏










