limit_conn_zone内存开销取决于独立客户端数而非并发连接数,每key约64字节;用$binary_remote_addr更省空间、提速;zone过小致LRU淘汰旧key,限流失效;需与limit_conn配合且不支持burst。

limit_conn_zone 的内存开销直接决定你能稳定跟踪多少个客户端,不是配得越大越好,也不是越小越省——关键在“够用且不浪费”。它不存完整连接对象,只存每个 key(比如 IP)的轻量状态:当前连接数、最后更新时间、超时标记等,每条记录约占用 64 字节。
单个 key 占多少内存?
实际观测和官方文档一致:每个唯一键(如一个 $binary_remote_addr)在共享内存区中平均消耗约 64 字节。这个值包含连接计数器、时间戳、锁结构及少量元数据。它不随并发连接数线性增长,而是随独立客户端数量增长——也就是说,1000 个 IP 各建 10 个连接,和 1000 个 IP 各建 1 个连接,内存占用几乎一样。
- 1 MB ≈ 支持 16,000 个独立 key
- 10 MB ≈ 支持约 160,000 个 IP(或其它键)
- 若业务日活 IP 约 50 万,建议 zone ≥ 32m(50w × 64B ≈ 32MB)
为什么用 $binary_remote_addr 而不是 $remote_addr?
$remote_addr 是点分十进制字符串(如 "192.168.1.100"),长度可变,最长 15 字节;而 $binary_remote_addr 是固定 4 字节(IPv4)或 16 字节(IPv6)的二进制表示。Nginx 内部哈希和查找都基于二进制格式,不仅节省空间,还提升匹配速度。对 IPv4 场景,单 key 内存可减少约 40%。
- 用 $remote_addr 存 10 万个 IP,key 部分就可能多占 1–2MB
- 代理环境需配合 real_ip 模块,确保 $binary_remote_addr 取到真实客户端 IP
- 若用 CDN 或四层 LB,应改用 $http_x_forwarded_for 的哈希或 $realip_remote_addr
zone 太小会怎样?
内存不足时,Nginx 会按 LRU(最近最少使用)策略淘汰旧 key。这意味着老 IP 的连接状态被清掉,新请求进来会被当作“新客户端”,绕过限流——看似没报错,实则限流失效。典型现象是:压测时部分 IP 突然能建远超 limit_conn 设定的连接数。
- 监控手段:通过 nginx stub_status 查看 Active connections,并结合 access 日志统计高频 IP 数量
- 排查方法:临时加大 zone(如从 5m → 20m),观察限流命中率是否回升
- 生产建议:初始配置预留 20% 余量,上线后根据 access.log 中 distinct $binary_remote_addr 数动态调整
和 limit_conn 配合时的关键细节
limit_conn_zone 只是“建表”,真正生效靠 limit_conn 指令。但要注意:它统计的是已进入 accept 队列并完成三次握手的连接,不包括 SYN 半连接(那是 tcp_syncookies 的事),也不统计 keepalive 空闲连接(除非该连接正在处理请求)。
- limit_conn addr 10 表示:每个 IP 最多有 10 个活跃请求连接同时处于 read/write 状态
- 若后端是长连接池(如 HTTP/2 + keepalive),单个浏览器可能复用连接,实际并发连接数远低于请求数
- 与 limit_req 不同,limit_conn 不支持 burst,也不做排队——超限连接直接被拒绝(返回 503),无缓冲机制


















