使用 $binary_remote_addr 替代 $remote_addr 可节省超50%内存,因其将IPv4/IPv6地址分别固定为4/16字节二进制存储,避免字符串开销;10MB zone实测可存约20万IPv4地址,配置仅需改写limit_req_zone变量并reload验证。

用 $binary_remote_addr 替代 $remote_addr 定义 limit_req_zone,是负载均衡层节省内存最直接有效的方式——关键不在“用了什么变量”,而在于它把 IP 地址存成固定长度的二进制值,彻底避开字符串管理开销。
为什么 binary_remote_addr 能省一半以上内存
Nginx 的限流状态存在共享内存 zone 里,真正吃内存的是每个客户端对应的 key 字段。不同写法差异巨大:
-
$remote_addr是字符串:IPv4 如"192.168.1.1"占 11 字节,IPv6 如"2001:db8::1"可达 39 字节;Nginx 需按最大可能长度预留空间,还要额外存指针和终止符 -
$binary_remote_addr是纯二进制:IPv4 固定 4 字节,IPv6 固定 16 字节;无编码、无长度判断、无动态分配,直接 memcpy 进哈希节点 - 实测单个 key 存储成本从平均 32–40 字节降至约 12–16 字节(含结构体头),综合节省超 50%
10MB zone 到底能存多少活跃 IP
别再信“1MB ≈ 1 万个 IP”这种粗略说法。真实容量取决于协议类型和内存对齐开销:
- IPv4 下,每个 IP 状态约占 44 字节(12 字节 key + 32 字节状态结构体)
- zone 内存约有 15–20% 用于哈希桶数组和链表指针等管理结构
- 10MB = 10,485,760 字节 → 扣除 18% 管理开销后剩约 8.6MB → 可存约 20 万个 IPv4 地址
配置写法与效果验证
两行配置对比就能看出差别,无需重启服务,仅 reload 即可观察:
- 低效写法:
limit_req_zone $remote_addr zone=bad:10m rate=5r/s; - 高效写法:
limit_req_zone $binary_remote_addr zone=good:10m rate=5r/s; - 验证方式:启动后执行
ps aux --sort=-vsz | head -5,主进程 VSZ 差值通常为 2–4MB,这就是 key 格式带来的纯内存节约 - 确认 Nginx 版本 ≥ 1.20(
nginx -V 2>&1 | grep -o "nginx version"),确保底层支持优化后的二进制存储路径
配合负载均衡场景的实用建议
在反向代理或网关层部署限流时,还需注意实际拓扑带来的影响:
- 若前端有 CDN 或四层 LB,
$binary_remote_addr拿到的是上一跳地址,需配合real_ip_header和set_real_ip_from提前还原真实客户端 IP - 集群中多个 Nginx 实例不能共用一个 zone,但可以统一用
$binary_remote_addr,保证各节点内存模型一致,便于横向扩容估算 - 当活跃 IP 超过 10 万,不建议单 zone 拉到 64MB 以上;可按业务域拆 zone(如
api_v1、upload),或结合map对内网/白名单跳过限流










