nginx可通过内置变量记录代理全链路耗时:$request_time、$upstream_connect_time、$upstream_header_time、$upstream_response_time,需在http块定义log_format并仅在proxy_pass location中启用,配合$upstream_addr和$upstream_status分析瓶颈。

要在 Nginx 日志中记录代理转发全过程的每个节点响应耗时,关键不是加一个开关,而是用对变量、配好格式、放在对的位置。只要后端返回了响应,Nginx 就能自动记录建连、首包、完整响应等阶段的时间,无需额外模块。
必须用的几个核心时间变量
这些变量在 proxy_pass 生效的 location 中天然可用,含义明确、精度毫秒:
- $request_time:整条链路总耗时(秒),从收到客户端第一个字节,到发完响应最后一个字节
- $upstream_connect_time:Nginx 与后端建立 TCP 连接所用时间(含 DNS 查询、TLS 握手)
- $upstream_header_time:从连接建立完成,到收到后端响应首行(状态码那一行)的时间
- $upstream_response_time:从发起请求,到接收完全部后端响应数据(header + body)的时间
日志格式要定义在 http 块里
在 nginx.conf 的 http 块中添加如下 log_format(注意变量顺序和引号写法):
log_format proxy_trace '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent '
'rt=$request_time uct="$upstream_connect_time" uht="$upstream_header_time" urt="$upstream_response_time" '
'upstream=$upstream_addr status=$upstream_status';
其中:
– uct/uht/urt 是常用缩写,方便日志解析;
– $upstream_addr 和 $upstream_status 必须一起记,才能知道每次耗时对应的是哪个节点、返回什么状态码。
只在 proxy_pass 的 location 中启用才有效
变量只在真正走代理的 location 中有值,静态服务或 rewrite 拦截的请求会显示为“-”。示例配置:
location /api {
proxy_pass http://my_backend;
access_log /var/log/nginx/api_trace.log proxy_trace;
}
注意:
– 如果 upstream 块定义了多个节点,且启用了重试(如 proxy_next_upstream error timeout),
$upstream_response_time 和 $upstream_status 会以逗号分隔,例如 "0.021, 0.087" 和 "502, 200",可据此匹配最终成功的一次;
– $upstream_connect_time 在连接复用时可能为 0,这是正常现象。
配合节点地址和状态一起分析才看得清瓶颈
单看耗时数字容易误判。比如某次 urt=0.5s,但 uct=0.48s,说明慢在建连(DNS 或 TLS),不是后端处理慢;如果 urt 和 uht 接近(如 0.123 vs 0.121),说明响应体很小,后端基本是即时返回 header 的。
建议在日志中固定包含以下字段组合:
– $upstream_addr(目标 IP:port)
– $upstream_status(对应每次尝试的状态码)
– $upstream_response_time(对应每次尝试的耗时)
– $request_time(用于对比 Nginx 自身开销)











