使用 $binary_remote_addr 或子网前缀作为限流 key 可显著降低内存占用:前者以固定字节长度减少哈希冲突,后者通过 map/geo 聚合 IP 实现子网共享计数器,配合合理 zone 大小设置可避免 OOM。

使用 limit_req_zone 时,若按客户端 IP 限流,默认会为每个唯一 IP 分配独立的内存槽位。当面对海量分散 IP(如移动用户、CDN 回源、爬虫)时,内存消耗会急剧膨胀。通过将 IP 地址转为二进制前缀(如 /24 或 /32)再哈希,可让同一子网的请求复用同一个限流槽位,显著降低共享内存占用。
用 $binary_remote_addr 替代 $remote_addr
Nginx 内置变量 $binary_remote_addr 是客户端 IP 的紧凑二进制表示(IPv4 固定 4 字节,IPv6 固定 16 字节),比字符串形式的 $remote_addr(如 "192.168.1.100" 占 11–15 字节)更短、更稳定,哈希冲突率更低,且不依赖字符串解析开销。
配置示例:
limit_req_zone $binary_remote_addr zone=perip:10m rate=5r/s;
按子网聚合:用 map + binary 预处理 IP 前缀
直接对全量 IP 限流仍可能撑爆内存。更优做法是先用 map 提取 IP 网络前缀(如 IPv4 取前 24 位),再转为二进制哈希。这样 /24 子网内所有 IP 共享一个计数器。
操作步骤:
- 定义 map 将 IPv4 地址映射为网络地址(如 192.168.5.22 → 192.168.5.0)
- 用
$binary_remote_addr的原始字节做哈希输入,但需配合 geo 或第三方模块提取前缀;更实用的是用geo指令预生成前缀变量 - 推荐写法(支持 IPv4/IPv6 自动适配):
geo $limited_ip {
default 0.0.0.0;
127.0.0.1/32 127.0.0.1;
# 实际中可留空,靠后续 map 处理
}
<p>map $remote_addr $ip_subnet {
~(?<ip>\d+.\d+.\d+). $ip.0; # IPv4 /24 前缀
~(?<ip>[0-9a-fA-F:]+:[0-9a-fA-F:]+): $ip::; # 简化 IPv6 /64(需更严谨匹配)
default $remote_addr;
}</ip></ip></p><p>limit_req_zone $ip_subnet zone=subnet24:5m rate=10r/s;</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/ai/2082" title="Flowise"><img
src="https://img.php.cn/upload/ai_manual/000/000/000/175679963322308.png" alt="Flowise" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/ai/2082" title="Flowise" class="overflowclass">Flowise</a>
<p class="overflowclass">一款开源的低代码AI应用开发工具,通过可视化流程编排帮助开发者构建聊天机器人、Agent和其他AI应用。</p>
</div>
<a rel="nofollow" href="/ai/2082" title="Flowise" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>注意:map 中正则提取前缀后仍是字符串,若要极致节省,可改用 Lua 或 NJS 在运行时构造固定长度二进制前缀,但多数场景用字符串前缀已足够压缩 90%+ 槽位。
合理设置 zone 大小与 key 长度
共享内存 zone 容量(如 10m)不是越大越好。每个 key 默认占用约 64 字节(含红黑树节点、时间戳、计数器等)。若 key 是 4 字节 $binary_remote_addr,理论最多存约 16 万条记录;若 key 是平均 12 字节的字符串 IP,则只剩约 5 万条。
关键建议:
- 始终优先用
$binary_remote_addr或预计算的固定长度前缀作为 key - 根据预期唯一 key 数量反推 zone 大小:例如预计 10 万个子网前缀,按 64 字节/槽 ≈ 6.4MB,设
zone=subnet:8m即可留余量 - 避免用长变量如
$host、$request_uri做限流 key,极易触发 OOM
验证与调优技巧
上线前务必确认实际 key 分布是否符合预期:
- 开启
error_log /path/to/log notice;,配合limit_req_status和自定义日志格式输出 key 值,采样检查是否真的聚合了子网 - 用
nginx -T | grep limit_req_zone确认配置已加载 - 观察
slab_alloc内存使用:ss -i | grep nginx或通过nginx -V 2>&1 | grep -o 'with.*memory'查模块支持情况 - 压测时监控
limit_req的 rejected/requeue 计数,突增可能意味着哈希碰撞或 zone 不足










