Nginx中limit_req限流拒绝的请求默认不记入access_log,需通过map定义$limit_rejected变量或直接使用$limit内置变量配合log_format记录,并结合grep/awk分析日志定位源头。

在 Nginx 中,被限流(如使用 limit_req)拦截的请求默认返回 503 状态码,但**不会自动记录到 access_log** —— 这是定位困难的根本原因。要准确识别这些请求来源,需主动配置日志记录逻辑。
确保限流拒绝请求被写入访问日志
Nginx 默认对 limit_req 触发的拒绝(即“excess”请求)不记入 access_log,因为它们甚至未进入常规请求处理流程。解决方法是:利用 log_format 中的变量 $limit 或更可靠的方式——结合 map 指令标记限流状态,并在日志中输出。
- 定义一个 map 变量,识别是否触发限流拒绝:
map $status $limit_rejected {
503 1;
default 0;
}- 扩展 log_format,加入该变量或直接用
$limit(需注意:$limit 是 limit_req 模块内部变量,仅在匹配 location 且启用 limit_req 时可用,值为“-”表示未超限,“1”“2”等表示超出请求数):
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'limit=$limit req_time=$request_time';- 在对应 location 中启用 limit_req,并确保 access_log 开启:
location /api/ {
limit_req zone=api burst=5 nodelay;
access_log /var/log/nginx/api_access.log main;
proxy_pass http://backend;
}这样,当请求因超限被拒绝时,$limit 值为数字(如 1),$status 为 503,日志行清晰可查。
用日志快速筛选限流 503 请求
生成日志后,可通过以下命令实时或离线排查:
- 查所有带限流标记的 503(假设你用了
limit=$limit):
grep 'status=503.*limit=[1-9]' /var/log/nginx/api_access.log
- 只看 IP 和请求路径(便于溯源):
awk '$9==503 && $14 ~ /limit=[1-9]/ {print $1, $7}' /var/log/nginx/api_access.log | sort | uniq -c | sort -nr其中 是 IP, 是 request(如 "GET /api/v1/user HTTP/1.1"),可快速定位高频攻击源或异常客户端。
补充:用 error_log 辅助诊断(调试阶段)
limit_req 拒绝请求时,会向 error_log 输出 warning 级别日志(如 limiting requests, excess: 1.000 by zone "api")。开启详细 error_log 可辅助交叉验证:
error_log /var/log/nginx/error.log warn;
注意:生产环境避免设为 info 或 debug,否则日志量激增。该日志不含客户端 IP,但能确认限流 zone 和触发频次,配合 access_log 更易归因。
验证是否真被限流而非其他 503
不是所有 503 都是限流导致。需排除后端服务不可用、upstream timeout、或自定义 return 503 等情况:
- 检查是否只有特定 path(如
/api/)出现 503,且集中在同一秒内多条,$limit值递增 → 基本确定是限流 - 对比 error_log 中是否有对应时间点的
limiting requests记录 - 临时关闭 limit_req,观察 503 是否消失;若仍存在,则来自 upstream 或其他逻辑
不复杂但容易忽略:关键在于让限流行为“可观察”,而不是依赖默认行为猜测。











