limit_conn基于共享内存实现跨worker全局连接计数,不支持单worker独立限流;关键在于合理配置limit_conn_zone大小与worker_connections,并确保真实IP识别、状态码与日志优化。

limit_conn 本身不按 worker 进程做隔离计数,它默认基于共享内存(shared memory zone)实现跨 worker 的全局统计。所以“单个 IP 在单个 worker 进程中的并发计数”不是 limit_conn 的设计目标,也不能直接配置——强行追求这种“每 worker 独立限流”反而会削弱防护效果,甚至导致策略失效。
真正需要关注的是:如何让 limit_conn 安全、稳定、不失效地工作在多 worker 环境下。这取决于两个关键点的协同:limit_conn_zone 的共享内存配置,以及 worker_connections 的合理设定。
✅ 正确理解 limit_conn 的计数机制
-
limit_conn的计数发生在 HTTP 请求处理阶段,依据你在limit_conn_zone中定义的 key(如$binary_remote_addr)进行哈希查找与原子增减; - 所有 worker 进程共用同一块共享内存区(由
zone=name:size指定),因此计数是进程间一致、全局准确的; - 它统计的是“当前活跃连接数”,即已完成三次握手、已读取请求头、尚未完成响应的连接;
- 不区分哪个 worker 接收了该连接,也不限制该连接落在哪个 worker 上。
⚠️ 错误认知:“把
limit_conn放在某个 worker 内部单独生效” —— Nginx 没有这种模式,也无需、不应模拟。
✅ 确保 limit_conn 安全运行的三项实操要点
共享内存区必须足够大,避免哈希冲突或写入失败
使用$binary_remote_addr(而非$remote_addr)可节省约 75% 内存;
10MB zone 约支持 16 万个独立 IP;若预估活跃 IP 数超 10 万,建议设为zone=perip:20m;
若日志中频繁出现limit_conn: cannot add connection,说明 zone 已满,需扩容。worker_connections必须显著高于单 IP 限值 × 预期并发 IP 数
例如:设limit_conn perip 10,预计最多 800 个不同 IP 同时访问 → 建议worker_connections ≥ 3000(留 2–3 倍余量);
同时检查系统级限制:ulimit -n至少为worker_processes × worker_connections的 1.2 倍;
若worker_connections过小,即使limit_conn允许连接,Nginx 也会因无可用 socket 句柄而返回500或直接断连。避免与其他模块逻辑冲突,尤其注意 location 层级叠加
limit_conn在server和location中均可配置,多个指令会取最严值(非相加);
例如:server块设limit_conn perip 20,其下location /api/又设limit_conn perip 5→ 实际生效为 5;
不建议在根location /和子路径重复设置相同 zone,易引发配置混乱和调试困难。
✅ 补充防护:让限流行为更可观、可运维
显式声明拒绝状态码与日志级别:
limit_conn_status 429;(比默认 503 更符合语义)limit_conn_log_level warn;(避免刷屏 error,又确保可被监控捕获)配合
limit_req做双维度控制:limit_conn防连接耗尽,limit_req防高频短连接刷接口;
二者可共用同一 zone 名(如都用perip),但推荐分设(如perip_conn/perip_req)便于独立调优。若前端有 CDN 或代理,务必配置真实 IP 识别:
set_real_ip_from 192.168.0.0/16;real_ip_header X-Forwarded-For;
否则$binary_remote_addr将始终是 CDN 节点 IP,导致所有用户被“捆扎限流”。
不复杂但容易忽略。










