单靠增大limit_req_zone内存无法支撑千万级ip长期限流,因每个ip状态槽占64字节,10mb仅存约16万个ip;应通过网段聚合、重点路径限流、白名单跳过、分级zone等策略压缩有效状态数。

单靠增大 limit_req_zone 的内存大小,并不能直接支撑“千万级 IP”的长期限流——这不是配置技巧问题,而是漏桶算法在共享内存中存储状态的固有成本决定的。关键不在“能不能存下”,而在于“是否需要全量持久记录”以及“如何降低有效状态数”。
为什么 10MB 只能存约 16 万个 IP?
Nginx 使用固定结构为每个活跃 IP 维护一个状态槽(含时间戳、计数器等),每个槽约占用 64 字节。1MB ≈ 16,000 个槽,10MB ≈ 160,000 个槽。这意味着:
- 若每秒有 10 万不同 IP 各发 1 个请求,1 秒内就可能填满 10MB 区域
- 超出后 Nginx 会自动淘汰 60 秒内无访问的旧记录;若仍不足,则新 IP 状态无法写入,限流逻辑失效(表现为部分 IP 不被限制)
- 千万级 IP 并发活跃时,即使按 IPv4 全地址空间算(约 42 亿),也远超内存承载能力
真正可行的千万级支持策略
不追求“记住所有 IP”,而是通过维度压缩与分层控制,让内存只服务于高价值或高风险流量:
-
按网段聚合限流:用
$geoip_country_code或自定义map将 IP 归属到国家/省份/运营商,key 改为$country_code。10MB 即可覆盖全球 200+ 国家 + 多级子区域 -
仅对重点路径限流:把
limit_req放在/login、/api/pay等敏感接口,而非根路径/。避免为静态资源、健康检查等低风险请求消耗状态槽 -
结合白名单跳过存储:用
map指令将 CDN 回源、监控探针、内部服务 IP 映射为空 key,使其完全不进入限流区,节省全部状态开销 -
分级 zone 配置:设置多个 zone,例如
zone=api_low:5m rate=1r/s(宽松兜底)、zone=api_strict:5m rate=0.1r/s(针对异常 UA),按需复用有限内存
实际部署建议
面向真实业务场景的配置示例:
- 基础防护:用
zone=perip:20m rate=5r/s覆盖日常爬虫和普通用户,20MB 支持约 32 万活跃 IP - 精准防控:对登录接口额外加一层
zone=login_brute:10m rate=3r/m(每分钟 3 次),key 可设为$binary_remote_addr$http_user_agent组合,防 UA 轮换爆破 - 全局压舱石:加一个极小 zone
zone=global_max:2m rate=100r/s,key 用$server_name,防止整个域名被刷垮 - 日志辅助判断:开启
limit_req_log_level warn,配合 access log 中的$limit变量,识别高频但未被限流的 IP 段,动态调整 map 白名单
本质上,Nginx 限流不是数据库,它不设计用来索引千万级独立键。把“支持千万级 IP”理解为“能应对千万级请求洪峰中的有效限流”,比纠结内存能否装下全部 IP 更贴近工程现实。











