nginx可通过$binary_remote_addr定义限流区域并应用于location实现单ip限流;需在http块配置limit_req_zone,location中用limit_req启用,代理环境下应结合real_ip模块提取真实ip。

直接在 Nginx 的 http 块中定义限流区域,再在代理接口所在的 location 中启用,就能限制单个客户端 IP 对后端接口的每秒请求数。关键在于用 $binary_remote_addr 作为 key,确保按真实客户端 IP 统计,而不是代理层 IP。
在 http 块中定义限流区域
把这段加到 /etc/nginx/nginx.conf 的 http { ... } 区域内:
limit_req_zone $binary_remote_addr zone=api_per_ip:10m rate=5r/s;
说明:
– $binary_remote_addr 是客户端 IP 的紧凑二进制表示,比 $remote_addr 更省内存;
– zone=api_per_ip:10m 表示建一个叫 api_per_ip、大小为 10MB 的共享内存区,能存约 16 万个 IP 的状态;
– rate=5r/s 表示每个 IP 每秒最多接受 5 个请求(支持 30r/m 等写法)。
在 location 中启用并应用到代理接口
假设你的后端 API 接口路径是 /api/,在对应 server 块里这样写:
location /api/ {
limit_req zone=api_per_ip burst=10 nodelay;
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
说明:
– burst=10 允许最多 10 个请求进入缓冲队列,超出部分才被拒绝;
– 加上 nodelay 后,这 10 个请求会立即转发给后端(不排队等待),适合容忍短时突发但防持续刷量;
– 若去掉 nodelay,超速请求会按设定速率匀速放行(有延迟)。
处理代理环境下的真实 IP
如果 Nginx 前面还有 CDN 或负载均衡(如 SLB、ALB),$binary_remote_addr 会变成上游代理 IP。此时需改用 $http_x_forwarded_for 或更稳妥的方式提取真实 IP:
- 先在
http块中用geo+map过滤可信代理,避免伪造头绕过限流; - 再定义 zone 时用
$realip变量(由set_real_ip_from和real_ip_header配合生成); - 例如:
limit_req_zone $realip zone=api_real:10m rate=3r/s;
验证与调优建议
生效后可通过日志和返回码确认效果:
- 加
limit_req_log_level warn;到http或location,让超限请求记为 warn 级别; - 配合自定义日志格式,输出
$limit(匹配的 zone 名)、$limit_rate(该 zone 的限速值)等变量; - 测试时用
ab -n 100 -c 20 http://yourdomain/api/test或wrk -t4 -c100 -d10s http://yourdomain/api/test观察 503 出现比例; - 若误伤正常用户,可适当调高
burst,或对登录态用户(如带有效Cookie)单独放宽限流。











