nginx按客户端ip独立限流需用$binary_remote_addr作key并合理设置zone内存大小,每个ip独享计数器与桶空间,配合real_ip模块还原真实ip,burst与nodelay控制突发处理策略。

Nginx 按客户端 IP 实现独立限流桶,核心是让每个 IP 拥有自己专属的计数器和桶空间,互不干扰。这靠 limit_req_zone 的 key 和 zone 配合实现,关键在于 key 要精确到单个 IP,且 zone 内存足够容纳大量 IP 条目。
用 $binary_remote_addr 作为 key
这是最常用也最推荐的方式。它把客户端 IP 转成紧凑的二进制格式,比 $remote_addr 节省内存约 60%。每个唯一 IP 对应一个独立计数器,天然实现“每 IP 一桶”。
-
$binary_remote_addr:识别真实客户端 IP(注意需配合real_ip模块处理代理场景) - 不要用
$remote_addr(字符串形式,占内存多、易被哈希冲突影响精度)
合理设置 zone 内存大小
zone=ip_limit:10m 中的 10m 不是给“一个桶”分配的空间,而是整个共享内存区大小,用于存储所有活跃 IP 的状态(时间戳、请求数、桶中剩余容量等)。
- 1MB 共享内存 ≈ 可存 1.6 万个 IP 的限流状态
- 若预估峰值有 50 万个不同 IP 访问,建议
zone=ip_limit:32m或更高 - 内存不足时,Nginx 会自动淘汰 60 秒内无活动的 IP 条目;若仍不够,新 IP 会被拒绝(返回 503)
配置示例:每 IP 独立限速 + 突发缓冲
http {
# 每个 IP 独立计数:10MB 内存,支持约 16 万 IP 并发跟踪,限速 5r/s
limit_req_zone $binary_remote_addr zone=ip_limit:10m rate=5r/s;
server {
location /api/ {
# 应用限流:允许最多 10 个突发请求,不排队延迟(立即处理)
limit_req zone=ip_limit burst=10 nodelay;
proxy_pass http://backend;
}
}
}
-
burst=10:每个 IP 自己的桶可暂存 10 个超额请求(不是全局共用) -
nodelay:这 10 个请求进入后立刻放行,不按漏桶节奏逐个释放(适合短时爆发) - 若去掉
nodelay,超出rate的请求会按固定间隔(如 200ms 一个)从队列放出
注意真实客户端 IP 的准确性
如果服务在 CDN 或反向代理(如 SLB、Nginx 前置)之后,$binary_remote_addr 默认拿到的是上一级代理 IP,导致多个用户共用一个桶。
需配合以下配置还原真实 IP:
set_real_ip_from 10.0.0.0/8; # 信任的代理网段 real_ip_header X-Forwarded-For; # 从该 header 读取原始 IP real_ip_recursive on;
否则限流会失效或误伤——例如所有微信用户走同一个出口 IP,就被当成一个人限流。
可选增强:区分登录用户与游客
若需更精细控制(比如登录用户限 20r/s,未登录限 2r/s),可用 $http_x_user_id 代替 $binary_remote_addr,由前端在请求头带上用户标识:
limit_req_zone $http_x_user_id zone=user_limit:10m rate=20r/s; # 后端需确保未登录请求不带该 header,或统一设为 "guest"
这样每个用户 ID(或固定标识)拥有自己的桶,比单纯按 IP 更精准,也避免同一局域网用户互相影响。











