使用$binary_remote_addr替代$remote_addr定义limit_req_zone可大幅降低内存开销:ipv4从32–40字节降至12–16字节,ipv6从最多39字节降至16字节,实测主进程vsz减少1–2mb。

用 $binary_remote_addr 替代 $remote_addr 定义 limit_req_zone,是实现高密度、低开销全局流控最直接有效的方式。核心不在于“加了什么功能”,而在于它把 IP 地址从可变长字符串压缩为定长二进制块,大幅降低共享内存中每个客户端状态的存储成本。
为什么二进制地址能压到极小内存
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 进哈希节点 - 实测显示:纯 IPv4 环境下单 key 存储成本从平均 32–40 字节降至约 12–16 字节(含结构体头),综合节省超 50%
配置写法与关键参数含义
必须在 http{} 块内定义,例如:
-
key:用
$binary_remote_addr作为唯一标识,确保粒度为 IP,且内存最省 -
zone:名称 + 大小,如
ip_limit:5m表示开辟 5MB 共享内存区;1MB 实际可存约 1.6 万 IPv4 地址状态(非粗略估算的“1 万”) -
rate:平均速率,单位支持
r/s或r/m;Nginx 内部以毫秒级精度控制(如10r/s≈ 每 100ms 放行一个)
搭配 limit\_req 实现可控流控行为
在 server 或 location 中调用已定义的 zone:
- burst:设置缓冲队列大小,允许突发请求临时排队;超出则触发拒绝或延迟逻辑
- nodelay:启用后,burst 内的请求立即处理(即瞬时吞吐 = rate + burst),超限直接返回 503;不加则排队等待,平滑释放
- 注意:仅定义
limit_req_zone不生效,必须配合limit_req才真正执行流控
验证内存是否真的降下来了
启动 Nginx 后,可通过进程内存映射确认效果:
- 运行
cat /proc/$(pidof nginx)/maps | grep "limit"查看共享内存实际占用 - 对比两组配置:
limit_req_zone $remote_addr zone=bad:5m ...与limit_req_zone $binary_remote_addr zone=good:5m ... - 同版本 Nginx(v1.20+)下,主进程 VSZ 差值通常达 1–2MB——这就是纯因 key 格式优化带来的收益











