接口被脚本刷、登录页被撞库、某个客户端突发大量请求拖垮后端,这些场景都可以先在 Nginx 层做限流。Nginx 提供两个常用模块:limit_req(限制请求速率)和 limit_conn(限制并发连接数)。参数里最容易搞混的是 burst 和 nodelay,本文用例子说清楚。
先在 http 块定义共享内存区,再在 location 中引用:
http {
limit_req_zone $binary_remote_addr zone=perip:10m rate=10r/s;
limit_req_status 429;
server {
location /api/ {
limit_req zone=perip burst=20 nodelay;
proxy_pass http://backend;
}
}
}各项含义:
$binary_remote_addr:以客户端 IP 为限流的键,比 $remote_addr 占用内存更小。zone=perip:10m:区域名与共享内存大小。官方文档给出的估算是 1MB 大约可存放 1.6 万个状态,具体以实际版本和平台为准。区域满了之后新请求会被拒绝,要按客户端数量预留。rate=10r/s:平均速率。Nginx 实际按毫秒粒度执行,10r/s 相当于每 100 毫秒放行一个请求。limit_req_status 429:被限流时返回的状态码,默认是 503,改成 429 更便于客户端识别。仅设置 rate 不设 burst 时,超过速率的请求会被直接拒绝,短时间内的正常小突发也会误伤。
burst=20:允许最多 20 个请求“排队”超出速率。超过 rate 的请求不会立即拒绝,而是放进队列,按 rate 的节奏逐个处理。队列满了才拒绝。nodelay:排队的请求会被延迟处理,用户感受到的是响应变慢,但最终都能成功。nodelay:队列中的请求立即处理,不再人为延迟,但这些 burst 位置仍按 rate 的速度“恢复”,恢复之前再来的请求会被拒绝。举例:rate=10r/s、burst=20、nodelay,一个客户端瞬间发来 30 个请求,前 21 个(1 个正常额度加 20 个 burst)立即处理,其余被拒绝,之后要等 burst 位置按每秒 10 个的速度恢复。
Nginx 1.15.7 起还支持 delay 参数:burst=20 delay=8 表示前 8 个超额请求不延迟,之后的排队延迟处理,介于两者之间,适合想兼顾体验与保护的场景。
http {
limit_conn_zone $binary_remote_addr zone=connperip:10m;
server {
location /download/ {
limit_conn connperip 5;
limit_rate 500k;
}
}
}这里限制每个 IP 最多 5 个并发连接,并限制单连接速度,适合下载等长连接场景。limit_req 管“每秒多少次”,limit_conn 管“同时多少个”,两者互补。
$remote_addr 是上游的地址,会让所有用户共用一个限流额度。需要用 real_ip 模块还原真实客户端 IP,并且只信任来自可信代理的头:set_real_ip_from 10.0.0.0/8;
real_ip_header X-Forwarded-For;
real_ip_recursive on;map 取请求头或 cookie 的值),或者适当放宽阈值。geo 与 map 为白名单 IP 生成空键,键为空的请求不会被限流:geo $limit {
default 1;
10.0.0.0/8 0;
}
map $limit $limit_key {
0 "";
1 $binary_remote_addr;
}
limit_req_zone $limit_key zone=perip:10m rate=10r/s;limit_req_log_level 控制拒绝日志的级别,错误日志里会出现 limiting requests, excess: ...。ab -n 100 -c 10 或 wrk,观察返回的 429 比例是否符合预期。nginx -t 检查语法,再 nginx -s reload。limit_req_dry_run on;,只记录不拒绝,先看日志评估影响再正式启用。rate 控制平均速度,burst 允许短时突发,nodelay 决定排队请求是否延迟处理。原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。