直接分析 access.log 中 $request_time 和 $upstream_response_time 字段可精准定位性能瓶颈:若前者显著大于后者(差值>200ms),问题在 nginx 层;若两者接近且偏高,问题在后端;若后者为“-”或极小而状态码为 502/504,则 upstream 连接失败;应关注 p90/p95 而非平均值。

直接看 access.log 里的 $request_time 和 $upstream_response_time 字段,比加监控、堆硬件更准、更快。关键不是看平均值,而是抓住“谁慢、在哪慢、为什么慢”这三件事。
盯住两个核心时间字段的差值
$request_time 是从收到第一个字节到发完最后一个字节的总耗时;$upstream_response_time 是 Nginx 和后端(如 Java 或 PHP 服务)之间真正通信所花的时间。
- 如果
$request_time明显大于$upstream_response_time(比如差值 >200ms),瓶颈大概率在 Nginx 层:SSL 握手慢、大 body 解析卡顿、gzip 压缩耗 CPU、proxy_buffering 关闭导致流式转发阻塞,或客户端网络差 - 如果两者接近且同时偏高(比如都 ≈1.5s),问题基本出在后端:数据库慢查询、同步逻辑阻塞、线程池打满、GC 暂停或连接池耗尽
- 若
$upstream_response_time为 “-” 或极小值(如 0.001s),但状态码是 502/504,说明 upstream 连接失败或超时,没真正走到业务逻辑
用百分位聚焦真实慢请求
平均响应时间容易被大量快请求拉低,掩盖退化。应重点看 P90 或 P95:
- 提取某接口的
$request_time列,排序后取前 5% 的值(例如用awk '{print $NF}' access.log | sort -n | tail -n +$(($(wc -l ) - 对比基线期(如 7 天前同一小时段)的 P95 值:上升超过 30% 且持续数小时,就是典型性能退化信号
- 优先筛选
status=200但$request_time > 2s的请求,排除错误干扰,专注“成功但很慢”的场景
结合 URL、状态码与 upstream 上下文交叉定位
单看耗时不够,要绑定业务和链路信息:
- 统计耗时 Top 10 的 URI 路径,看是否集中在某个接口(如
/api/order/list)、某类资源(如大图/static/img/report_2026.jpg) - 检查高耗时请求是否伴随异常状态码:502/504 指 upstream 超时;499 表示客户端主动断连(常见于页面跳转或刷新);500 可能对应后端未捕获异常
- 搭配
$upstream_addr和$upstream_status看具体哪台后端实例响应异常(例如10.0.1.8:8080出现连续高$upstream_response_time) - 若日志中
$upstream_response_time是逗号分隔(如0.002, 0.001, 1.247),说明触发了重试,最后一段突增往往暴露毛刺根源
注意日志自身可能引入误差
日志写入不是零成本,在高并发下可能反成瓶颈:
- Traefik 或 Nginx 在极端压力下,access log 写入卡顿会导致
$request_time虚高,表现为一批随机出现的 1s+ “假慢请求” - Nginx 开启
buffered_logs或使用异步日志模块(如配合 syslog),可降低对主线程影响 - 确认日志落盘方式:本地磁盘易受 IO 瓶颈拖累;发远程日志服务则可能因网络延迟引入时间偏差











