Nginx 无法原生记录客户端真实请求排队耗时,但可通过 $upstream_queue_time(1.19.1+ 支持,需启用 queue 指令或后端返回 X-Queue-Time)精准获取;否则可用 $request_time - $upstream_response_time 粗略估算,或借助 OpenResty 的 Lua 模块增强采集。

在 Nginx 中,log_format 本身不能直接记录“客户端真实的请求排队耗时”,因为 Nginx 并不原生暴露排队等待时间(比如请求在 accept 队列或 worker 进程任务队列中停留的时间)。但你可以通过组合 内置变量 和 上游响应头(如果后端支持),或借助 第三方模块(如 nginx-module-vts 或自定义 patch),来**逼近或间接反映**真实排队延迟。最实用、广泛兼容的方式是:利用 $request_time 与 $upstream_response_time 的差值,再结合 $upstream_queue_time(需启用对应模块)来估算。
确认是否支持 $upstream_queue_time(推荐起点)
Nginx 官方从 1.19.1 版本起原生支持 $upstream_queue_time 变量,前提是:
- 使用了
proxy_pass/fastcgi_pass等 upstream 转发指令; - 后端服务(如 OpenResty、某些 Go/Java 服务)在响应头中返回了
X-Queue-Time或类似字段(Nginx 会自动提取并赋值给该变量); - 或你启用了
queue指令(如queue 100 timeout=5s;)——此时 Nginx 会在内部维护一个请求队列,并填充$upstream_queue_time。
✅ 启用示例(在 upstream 块中):
upstream backend {queue 200 timeout=3s;
server 127.0.0.1:8000;
}
这样,每个进入该 upstream 队列的请求,其排队耗时(从入队到被分发给后端)就会被记录为 $upstream_queue_time。
定义 log_format 包含排队相关变量
在 http 块中定义日志格式,显式包含关键耗时字段:
'$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'$request_time $upstream_response_time $upstream_queue_time';
access_log /var/log/nginx/access_queue.log queue_log;
其中:
-
$request_time:整个请求处理总耗时(从读取首字节到日志写入,单位秒,精度毫秒); -
$upstream_response_time:Nginx 等待后端响应的时间(可能多个值,用逗号分隔); -
$upstream_queue_time:请求在 upstream 队列中等待的时间(仅当启用queue或后端返回对应 header 时有效)。
没有 queue 指令?尝试用差值粗略估算排队开销
若无法启用 queue,且后端不返回队列时间,可将 $request_time - $upstream_response_time 视为“Nginx 自身处理 + 排队 + 网络延迟”的综合耗时。虽然不精确,但在高并发压测中,若 $upstream_response_time 很稳定(如恒为 20ms),而 $request_time 显著拉长(如 300ms),则多出的部分大概率来自内核 accept 队列积压或 worker 争抢,具有可观测价值。
⚠️ 注意:$upstream_response_time 是字符串(如 "0.023, 0.025"),需用 Lua 或日志分析工具(如 awk、Loki + Promtail)做后处理提取首个值再计算差值。
进阶:用 Lua 获取更细粒度排队指标(OpenResty)
如果你使用 OpenResty,可在 access_by_lua_block 中调用 ngx.now() 打点,或读取 ngx.var.upstream_queue_time(同 Nginx 变量),甚至 hook 到 init_worker_by_lua_block 统计队列长度。例如:
local qtime = tonumber(ngx.var.upstream_queue_time) or 0
ngx.var.my_queue_time = string.format("%.3f", qtime)
}
log_format lua_log ... '$my_queue_time';
这种方式灵活性更高,适合需要定制化排队监控的场景。


















