$limit_req_status是Nginx限流模块内置变量,用于日志中标识请求限流状态,取值包括passed、rejected、delayed、delayed_dry_run,需在log_format中定义并配合limit_req指令使用,不可仅依赖HTTP状态码判断限流效果。

$limit_req_status 是 Nginx 官方限流模块 ngx_http_limit_req_module 提供的一个内置变量,用于在日志中明确标识当前请求是否被限流规则拦截,以及具体拦截阶段的状态。它不输出数字状态码,而是返回字符串值,对排查限流生效逻辑、分析拦截分布、优化策略配置非常关键。
它的取值含义与实际对应场景
该变量只在 log_format 中使用(如写入 access_log),且仅当请求经过 limit_req 指令时才有意义。常见取值如下:
- passed:请求未触发限流,顺利通过(包括未命中任何 limit_req 规则,或虽命中但未超限);
- rejected:因超出速率/突发容量,被直接拒绝(返回 503,默认行为);
-
delayed:请求被延迟排队(启用
burst且设置了nodelay以外的配置),但最终仍被处理; -
delayed_dry_run:仅在调试模式下出现(
limit_req ... dry_run),表示“本次会拦截,但实际未拦截”,用于灰度验证规则。
如何在日志中正确记录并分析
需先在 log_format 中引入该变量,再确保对应 location 启用了限流:
- 定义日志格式:
log_format main '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$limit_req_status"'; - 在 server 或 location 块中配置限流:
limit_req zone=api burst=10 nodelay;(注意:无nodelay才可能出现delayed); - 重启 Nginx 后,访问日志中最后一列即为状态值,可直接用
awk、grep或 ELK 统计分布,例如:awk '{print $13}' access.log | sort | uniq -c | sort -nr。
为什么不能只看响应状态码来判断限流?
因为限流拦截结果与 HTTP 状态码不是一一对应的:
-
rejected通常返回 503,但可通过limit_req_status 429改为返回 429; -
delayed请求最终成功,状态码是 200,但实际经历了排队延迟,用户体验已受损; - 若配置了多个
limit_req指令(如按 IP + 按接口分别限流),$limit_req_status只反映**最后生效的那个指令**的结果,需结合$limit_req_status和日志上下文(如匹配的 zone 名)交叉判断。
实用调试建议
- 上线新限流策略前,先加
dry_run,观察delayed_dry_run出现频率,预估真实拦截量; - 对高敏感接口,可在日志中同时记录
$limit_req_status和$limit_req_key,定位具体被限的 key(如用户 ID 或 token 前缀); - 避免在未启用限流的 location 中引用该变量——此时值为空字符串,易干扰统计,建议配合
map设置默认值,例如:map $limit_req_status $req_limited { "" "none"; default $limit_req_status; }。

















