在http块中配置limit_req_zone需用$binary_remote_addr变量和至少5m共享内存(推荐10m),否则因地址字符串过长或内存不足导致限流失效;burst设缓冲区容量,nodelay决定是否立即放行burst内请求,二者需配合使用;路径级限流须用map或set定义$limit_key变量并配limit_req_zone于http级;503可借error_page重定向至内部location返回429及json;但nginx限流不控制后端耗时,需应用层协同防护。

nginx.conf 里怎么配 limit_req_zone 才有效
直接在 http 块里加 limit_req_zone 指令,但很多人漏掉两个关键点:变量选择和共享内存大小。用 $binary_remote_addr 而不是 $remote_addr,能压缩 IPv4/IPv6 地址为固定 4–16 字节,避免哈希冲突导致限流失效;共享内存区(如 zone=burst:10m)至少要 5m,10m 更稳妥——1m 内存约存 1.6 万个会话,小流量够用,高并发下内存不足会导致限流退化为“不生效”。
常见错误是写成 limit_req_zone $remote_addr zone=burst:1m rate=10r/s,结果压测时大量请求绕过限制,实际就是地址字符串太长 + 内存太小,桶被挤掉或哈希碰撞太高。
limit_req 指令的 burst 和 nodelay 参数怎么组合使用
burst 是漏桶的“缓冲区容量”,nodelay 决定是否允许突发请求立刻通过(不排队)。二者必须一起理解,不能只看文档字面:
-
limit_req zone=burst burst=20;:允许最多 20 个请求排队,超了就 503;每个请求按速率匀速放行(比如 10r/s,排队请求平均间隔 100ms) -
limit_req zone=burst burst=20 nodelay;:前 20 个请求立刻放行,第 21 个开始才限速;适合登录、秒杀等需要“首包快”的场景 -
limit_req zone=burst burst=0;:严格按速率来,不缓存、不排队,超了直接 503;适合 API 接口保底稳定性
注意:nodelay 不等于“不限流”,它只是把 burst 容量内的请求一次性透传,后续仍受 rate 控制。误加 nodelay 又设大 burst,等于变相放开限流。
如何对不同路径或接口单独限流(比如 /api/pay 严控,/static 放开)
靠 location 块嵌套 limit_req,但必须确保 limit_req_zone 定义在 http 级且变量能覆盖目标路径。典型做法是用自定义变量区分接口类型:
limit_req_zone $limit_key zone=api:10m rate=5r/s;
server {
location /api/ {
set $limit_key "$binary_remote_addr-api";
limit_req zone=api burst=10 nodelay;
}
location /static/ {
set $limit_key "";
# 空字符串不触发限流(nginx 会跳过)
}
}
更安全的方式是用 map 构建变量,避免 set 在某些条件下不执行:
map $request_uri $limit_key {
~^/api/pay/ "$binary_remote_addr-pay";
~^/api/order/ "$binary_remote_addr-order";
default "";
}
limit_req_zone $limit_key zone=pay:5m rate=2r/s;
别直接在 location 里写 limit_req_zone——语法不支持,配置会加载失败。
限流后返回 503 怎么改成 429 或返回 JSON 提示
nginx 本身不支持直接改限流状态码,但可通过 error_page 重定向到一个内部 location,再由它返回自定义响应:
limit_req zone=burst burst=5;
error_page 503 = @rate_limit_exceeded;
<p>location @rate_limit_exceeded {
return 429 '{"code":429,"msg":"Too Many Requests"}';
add_header Content-Type "application/json";
}</p>
注意三点:一是 = 符号不能省,否则变成外部重定向;二是 return 后不能跟空格或换行,否则解析报错;三是如果用了 proxy_pass,这里必须确保没其他模块(如 echo 模块)干扰 header 输出。
另外,429 是标准语义码,但老版本浏览器或监控工具可能识别不了,生产环境建议同时加 add_header X-RateLimit-Limit "5"; 等标准限流头,方便客户端解析。
真正难的是压测时发现“看起来限住了,但数据库还是被打挂”——因为 nginx 限流只管连接和请求频率,不管后端处理耗时。如果单个请求要查 10 张表,限 10r/s 也可能拖垮 DB。这时候得配合应用层熔断或异步队列,nginx 限流只是第一道门,不是万能锁。











