limit_req_zone 本身不提供缓存功能,仅实现实时漏桶限流;千万级稳定限流需依托精准内存建模(如按活跃IP基数计算64字节/个)、分层zone设计(按路径敏感度拆分)及外部协同(WAF初筛+Redis黑名单)。

直接说结论:limit_req_zone 本身不提供缓存功能,它做的是实时漏桶限流;所谓“缓存高可用流控”其实是误用术语。真正要支撑千万级并发下的稳定限流,关键不是靠“缓存 IP 状态”,而是通过精准内存建模 + 分层 zone 设计 + 外部协同,让有限的共享内存只服务真正需要控制的流量维度。
按活跃基数精确算内存,别碰10m这种拍脑袋配置
每个活跃 IP(用 $binary_remote_addr)在 64 位 Nginx 中实际占用约 64 字节,含计数器、时间戳、哈希元数据等。1MB ≈ 存 1.6 万个 IP。若监控确认峰值活跃 IP 是 800 万:
- 理论最小内存 = 8,000,000 × 64 ÷ 1,048,576 ≈ 488 MB
- 生产必须加 20%~30% 冗余,建议配 zone=ip_limit:600m
- 写成 100m 或 200m —— 连 30 万 IP 都存不下,千万级下等于没开限流
用降维 key 替代全量 IP,把千万级压到几百个逻辑单元
硬记千万个独立 IP 是内存灾难。应放弃 “每个 IP 一个槽位” 的思路,改用聚合或身份标识:
- 按地域:用 $geoip2_country_code 或 $http_x_forwarded_for 的前两段(如 192.168),10MB 就能覆盖全球国家+主要运营商
- 按用户身份:登录态走 $http_x_user_id,未登录回落到 IP 前缀,真实用户数远小于 IP 总量
- 按 CDN 回源特征:组合 $http_x_real_ip + $server_name,把同一源站对同一客户的请求视为一个逻辑 key
分层 zone 设计,让内存各司其职不打架
单一大 zone 在千万级下会成为锁瓶颈和状态抖动源。应按路径敏感度、行为类型拆开:
-
高频敏感路径:如
/login单独配zone=login_strict:20m rate=3r/m,key 可加 UA 防轮换爆破 -
低频静态资源:用轻量 zone,如
zone=static_light:30m rate=100r/s,不设 burst,省空间 -
全局兜底:极小 zone 如
zone=global_flood:2m rate=200r/s,key 用$server_name,防域名级打垮
必须搭配外部机制,Nginx 限流只是第一道筛子
纯靠 Nginx 共享内存无法长期承载千万级独立状态。需叠加防御纵深:
- 前置 WAF 或 LVS 层做连接速率/包速率初筛,过滤明显扫描和 CC 流量
- 后端服务发现高频异常 IP,写入 Redis 黑名单,Nginx 用 lua-resty-redis 实时查表跳过限流逻辑
- 开启 limit_req_status 429 和自定义 error_page,让客户端明确感知被限,避免重试风暴










