如何用limit_req_zone和$binary_remote_addr节省50%内存空间?
- 内容介绍
- 相关推荐
本文共计748个文字,预计阅读时间需要3分钟。
直接使用 `$binary_remote_addr` 替代 `$remote_addr` 作为 `limit_req_zone` 的 key,可以在共享内存中节省超过 50% 的空间——这不是优化技巧,而是 Nginx 底层数据存储机制决定的固有优势。
为什么 $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 在 IPv4 环境下,从平均 32–40 字节降至约 12–16 字节(含结构体头),综合节省超 50%
真实内存占用怎么算
别再信“1MB ≈ 1 万个 IP”这种粗略估算。实际容量取决于协议类型和内存管理开销:
- IPv4 下,每个
$binary_remote_addrkey 实际占用约 44 字节:12 字节 key 数据 + 32 字节状态结构体(计数器、时间戳、指针等) - 共享内存 zone 有 15–20% 开销用于哈希桶数组、链表指针等管理结构
- 例如 10MB zone:10 × 1024 × 1024 = 10,485,760 字节 → 扣除 18% 后剩约 8.6MB → 可存约 20 万个 IPv4 地址
配置对比与验证方法
两行配置,效果差异明显,且无需重启全量服务即可验证:
- 低效写法:
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 的内存节约 - 确认版本:用
nginx -V 2>&1 | grep -o "built by.*"确保是 v1.20+,该优化在较新版本中更稳定
搭配 map 或 set 进一步精控
如果需对特定 IP 放行或聚合限流,可结合 map 或 set 动态构造 key,仍保持二进制压缩优势:
- 例:排除内网 IP 不限流:
map $remote_addr $limit_key { default $binary_remote_addr; 192.168.1.100 ""; },空字符串不触发限流 - 例:按业务分层限流:
set $limit_key "$binary_remote_addr-api";,key 仍以二进制 IP 开头,长度可控 - 关键点:只要 key 的核心部分含
$binary_remote_addr,就能保住主要压缩收益
本文共计748个文字,预计阅读时间需要3分钟。
直接使用 `$binary_remote_addr` 替代 `$remote_addr` 作为 `limit_req_zone` 的 key,可以在共享内存中节省超过 50% 的空间——这不是优化技巧,而是 Nginx 底层数据存储机制决定的固有优势。
为什么 $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 在 IPv4 环境下,从平均 32–40 字节降至约 12–16 字节(含结构体头),综合节省超 50%
真实内存占用怎么算
别再信“1MB ≈ 1 万个 IP”这种粗略估算。实际容量取决于协议类型和内存管理开销:
- IPv4 下,每个
$binary_remote_addrkey 实际占用约 44 字节:12 字节 key 数据 + 32 字节状态结构体(计数器、时间戳、指针等) - 共享内存 zone 有 15–20% 开销用于哈希桶数组、链表指针等管理结构
- 例如 10MB zone:10 × 1024 × 1024 = 10,485,760 字节 → 扣除 18% 后剩约 8.6MB → 可存约 20 万个 IPv4 地址
配置对比与验证方法
两行配置,效果差异明显,且无需重启全量服务即可验证:
- 低效写法:
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 的内存节约 - 确认版本:用
nginx -V 2>&1 | grep -o "built by.*"确保是 v1.20+,该优化在较新版本中更稳定
搭配 map 或 set 进一步精控
如果需对特定 IP 放行或聚合限流,可结合 map 或 set 动态构造 key,仍保持二进制压缩优势:
- 例:排除内网 IP 不限流:
map $remote_addr $limit_key { default $binary_remote_addr; 192.168.1.100 ""; },空字符串不触发限流 - 例:按业务分层限流:
set $limit_key "$binary_remote_addr-api";,key 仍以二进制 IP 开头,长度可控 - 关键点:只要 key 的核心部分含
$binary_remote_addr,就能保住主要压缩收益

