直接用 $binary_remote_addr 替代 $remote_addr 作为 limit_req_zone 的 key 可节省超 50% 共享内存,因其 ipv4 固定占 4 字节、ipv6 占 16 字节,而 $remote_addr 字符串形式需 11–39 字节并含终止符与对齐填充,实测单 key 从 32–40 字节降至 12–16 字节。

直接用 $binary_remote_addr 替代 $remote_addr 作为 limit_req_zone 的 key,就能实打实节省超 50% 共享内存——这不是调优技巧,而是 Nginx 底层存储机制决定的硬性收益。
为什么 $binary_remote_addr 能省一半以上内存
Nginx 的限流状态(每个 IP 的计数器、时间戳、哈希指针等)都存在共享内存 zone 中,真正吃内存的是区分客户端的 key 字段:
-
$remote_addr是字符串,IPv4 如"192.168.1.1"占 11 字节,还要加空终止符、内存对齐填充,实际占用常达 16–24 字节;IPv6 字符串最长可达 39 字节,开销更大 -
$binary_remote_addr是纯二进制值:IPv4 固定 4 字节,IPv6 固定 16 字节;无编码、无终止符、无动态分配,直接 memcpy 到哈希节点 - 单个 key 在 IPv4 场景下,平均从 32–40 字节降至约 12–16 字节(含结构体头),加上哈希桶管理开销,综合节省超 50%
配置写法与效果对比
只需改一行配置,reload 即可生效,无需重启:
- 低效写法:
limit_req_zone $remote_addr zone=bad:10m rate=5r/s; - 高效写法:
limit_req_zone $binary_remote_addr zone=good:10m rate=5r/s;
实测 10MB zone:用 $remote_addr 最多支撑约 1.2 万个 IP;换成 $binary_remote_addr 后可稳定容纳约 20 万个 IPv4 地址,提升超 15 倍。启动后执行 ps aux --sort=-vsz | head -5,主进程 VSZ 通常下降 2–4MB,就是纯内存节约。
代理场景下必须配合 realip 模块
如果 Nginx 前有 CDN、云 WAF 或负载均衡器,$binary_remote_addr 默认拿到的是代理 IP(比如全是 10.0.0.1),会导致所有用户被捆在一起限流:
- 必须启用
ngx_http_realip_module,并配置set_real_ip_from和real_ip_header - 然后使用
$realip_remote_addr(或$http_x_forwarded_for配合 map 提取首 IP)作为限流 key - 切勿直接对
$http_x_forwarded_for使用$binary_remote_addr—— 它仍是字符串,不压缩
搭配 map 实现更精细控制
在保持二进制压缩优势的前提下,可用 map 动态构造 key:
- 内网 IP 白名单跳过限流:
map $remote_addr $limit_key { default $binary_remote_addr; 192.168.0.0/16 ""; } - 按业务分层限流:
set $limit_key "$binary_remote_addr-api";或"$binary_remote_addr-$host",key 仍以紧凑二进制开头 - 避免用
map尝试把$remote_addr“转成”二进制——Nginx 不支持运行时编码,无效











