应使用 $upstream_response_time 而非 $request_time 监控后端响应时间,它精确记录代理请求到接收响应头的耗时,需配合自定义日志格式、过滤无效值(如“-”或0.000)、与 $request_time 差值分析定位瓶颈,并接入可观测工具做分位数统计。

不能直接用 $request_time 监控后端响应时间——它反映的是 Nginx 全链路耗时,包含上传、自身处理、网络传输和响应发送等环节。真正代表后端响应快慢的,是 $upstream_response_time。用对变量、配好日志、结合状态码和对比分析,才能准确定位后端性能问题。
正确采集 $upstream_response_time 并绑定专用日志格式
该变量只在使用 proxy_pass、fastcgi_pass 等代理指令时有效,单位为秒(含毫秒精度),记录从发起请求到收到响应头的时间。需显式写入自定义日志格式,避免覆盖内置格式:
- 在
http块中定义新格式,例如:log_format upstream_log '$remote_addr [$time_local] "$request" $status $body_bytes_sent "$upstream_addr" $upstream_response_time $request_time'; - 在对应
location或server块中启用:access_log /var/log/nginx/upstream.log upstream_log; - 执行
nginx -t && nginx -s reload生效后,检查日志是否出现类似0.128或0.045, 0.312(重试场景)的值
识别并过滤无效或干扰值
$upstream_response_time 是字符串类型,可能含多个逗号分隔值或短横线(-),直接统计会出错:
- 值为
-表示连接失败、超时或后端不可达,应单独归类统计失败率 - 多个值(如
0.021, 0.437)说明触发了重试,建议采集时取首个非-值作为主耗时,或标记重试次数 - 若值恒为
0.000,需检查是否因proxy_buffering off导致未等待响应头就返回,或后端未正确设置 HTTP 状态码
通过差值对比快速定位瓶颈层
单看 $upstream_response_time 只知后端“花了多久”,必须与 $request_time 配合判断问题归属:
- 若
$request_time ≈ $upstream_response_time(差值 - 若
$request_time − $upstream_response_time > 0.2s,说明 Nginx 本机开销大:可能是复杂rewrite、大量if判断、SSL 卸载压力高、或日志写入磁盘慢 - 若
$upstream_response_time正常但$request_time极高,且状态码为499,大概率是客户端中断上传;若为504,则需调大proxy_read_timeout
接入可观测工具做分位数与趋势分析
原始日志需交由支持聚合计算的系统处理,才能看出真实分布:
- Prometheus + nginx-prometheus-exporter:启用
--enable-upstream-stats后,指标nginx_upstream_response_msecs支持直方图聚合,在 Grafana 中用histogram_quantile(0.5, ...)查中位数,histogram_quantile(0.95, ...)查 P95 - Loki + Grafana:用 LogQL 提取字段并计算,例如:
{job="nginx"} |~ `GET.*` | regexp `"upstream_response_time\s+(\d+\.\d+)"` | unwrap __error__ | quantile_over_time(0.90, __error__[5m]) - 本地快速排查:用
awk '$NF > 1 {print $(NF-1)}' upstream.log | sort -n | tail -10查最慢的 10 次后端响应(假设$upstream_response_time是倒数第二列)











