排查接口变慢的问题时,第一步通常是看访问日志里的耗时字段。但Nginx提供了两个非常相似的时间变量:$request_time和$upstream_response_time,很多人分不清它们的边界,导致监控数据看起来一切正常,用户却持续投诉卡顿。搞清楚这两个变量的含义,是搭建后端响应时间监控体系的基础。

两个时间变量到底有什么区别
$request_time统计的是Nginx从收到客户端请求的第一个字节开始,直到把响应最后一个字节发送完毕所经过的总时间。它包含了Nginx自身的处理开销、向上游发起连接的时间、上游返回数据的时间,以及向客户端传输响应体的网络耗时。也就是说,客户端网速慢、下载大文件耗时长,都会把这个值撑大,但它并不能说明后端服务本身慢。
$upstream_response_time则聚焦于后端链路,统计的是从Nginx向上游(比如PHP-FPM、Tomcat、Go服务)建立连接开始,到上游返回完整响应为止的时间。如果请求经过了多级上游代理,这个值会是多段耗时的累加,中间用逗号分隔。它剔除了客户端网络传输的干扰,是衡量后端服务真实处理能力更合适的指标。
两者的差值也有诊断价值。当$request_time远大于$upstream_response_time时,瓶颈往往出在客户端网络、Nginx缓冲区配置或者大响应体的传输上;当两个值都很高且接近时,则应该把排查重点放在后端服务、数据库查询、外部接口调用等环节。当请求没有经过任何上游处理(比如直接命中本地静态文件或缓存)时,$upstream_response_time会是一个横杠字符,做统计时需要过滤处理。
如何在日志中配置响应时间字段
默认的combined日志格式并不包含耗时信息,需要自定义log_format。下面是一个生产环境常用的配置示例,把请求时间、上游响应时间、上游地址一起记录下来,方便后续分析:
log_format timing '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'rt=$request_time urt=$upstream_response_time '
'ua=$upstream_addr "$http_user_agent"';
access_log /var/log/nginx/access.log timing;
# 如果响应体较大,建议开启缓冲,避免日志写盘阻塞worker
access_log /var/log/nginx/access.log timing buffer=64k flush=5s;需要注意的是,$upstream_response_time的精度默认是毫秒级,且在没有上游参与时值为横杠,日志分析脚本里要做兼容。另外,如果使用了proxy_buffering关闭的场景(比如SSE流式响应),这个变量反映的是收到上游响应头的时间,与实际完整传输耗时可能存在差异,流式场景建议结合$request_time一起看。
还可以针对不同业务配置不同的日志文件,比如把慢请求单独切分出来。Nginx本身不支持在log指令中做条件判断,但可以借助map模块给耗时打上标记,再由日志采集端过滤:
map $upstream_response_time $is_slow {
default 0;
"~^\d\d" 1; # 大于等于10秒的请求标记为慢请求
"~^\d\.\d{2,}" 1; # 或者秒级带小数的也标记
}
access_log /var/log/nginx/slow.log timing if=$is_slow;
access_log /var/log/nginx/access.log timing;基于日志和指标的监控方案落地
日志采集方案是目前最普遍的做法。通过Filebeat或Fluent Bit把access.log采集到Elasticsearch,在Kibana中就能做耗时分布分析:按P50、P90、P95、P99分位数绘制曲线,观察长尾请求占比;再按upstream_addr维度下钻,快速判断是某一台后端机器劣化还是整体问题。对于多级代理架构,记得每一层的Nginx都记录时间字段,串联trace id后可以还原请求在整条链路上的耗时分布。
如果希望有更实时的告警能力,可以采用指标方案。一种是使用nginx-module-vts这类第三方模块,它直接在Nginx内部暴露按upstream分组的响应时间直方图,配合Prometheus抓取非常方便。另一种是在日志侧用Prometheus的mtail或者Grafana的Loki做指标转换。下面给出一个vts模块配合Prometheus的基础抓取配置思路:
scrape_configs:
- job_name: nginx-vts
metrics_path: /status/format/prometheus
static_configs:
- targets:
- 192.168.0.10:8080
- 192.168.0.11:8080告警规则的设置也有讲究。直接对平均值告警容易被少数超长请求拉高或者被海量快请求稀释,更稳妥的做法是关注P95和P99分位数,并结合请求量做双重判断:只有QPS超过一定阈值且分位数超标的告警才触发,避免夜间低流量时的误报。常见的规则示例是:某upstream的P95响应时间连续五个采样周期超过500毫秒,且期间每秒请求数不低于10,就发送告警并附带该upstream最近耗时的直方图截图,方便值班同学第一时间判断影响面。
最后提醒一点,监控的意义在于对比而非绝对数值。接口从80毫秒涨到300毫秒才是需要关注的信号,单纯看绝对值意义不大。建立基线、观察趋势、关联发布记录,才是响应时间监控真正的价值所在。把$upstream_response_time纳入日志和指标体系后,定位慢接口就从凭感觉变成了看数据,绝大多数性能问题的排查时间都能缩短一半以上。
Nginxupstream_response_time响应时间监控修改时间:2026-08-31 13:05:58