prometheus采集nginx upstream响应耗时需结构化指标:①用nginx-prometheus-exporter解析access_log(含$upstream_response_time);②用nginx-module-vts+exporter拉取实时json;③用openresty+lua自定义打点;最后用histogram_quantile计算p95/p99。

要用 Prometheus 采集 Nginx 后端 upstream 响应耗时,关键不是“把日志扔给 Prometheus”,而是让指标可量化、带标签、能聚合。原生日志里的 $upstream_response_time 是字符串,含逗号分隔、空值、“-”和重试痕迹,Prometheus 无法直接消费——必须先结构化。
用 nginx-prometheus-exporter 解析 access_log(推荐入门方案)
这是最轻量、无需改 Nginx 源码的方式,适合已用标准 access_log 的场景:
- 确保 access_log 格式中显式包含
$upstream_response_time,例如:
log_format upstream_fmt '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $upstream_response_time $upstream_addr $upstream_status'; - 启动 exporter 时加参数:
--enable-upstream-stats --nginx.scrape-uri=http://127.0.0.1:8080/nginx_status(注意:它实际解析的是你配置的 access_log 文件路径,非 /nginx_status;该参数名易误导,实为指定日志文件位置) - 它会自动提取
$upstream_response_time字段,过滤掉“-”和空值,按$upstream_addr和$upstream_status打标,暴露直方图指标:nginx_upstream_response_time_seconds_bucket{le="0.1",upstream="10.20.30.41:8080",status="200"} - ⚠️ 注意:若日志中该字段是多值(如
"0.012, 0.045"),exporter 默认取第一个非空值;如需最终成功那次,建议提前在 Nginx 中用 Lua 或 map 预处理成单值
用 nginx-module-vts + exporter 拉取实时 JSON 状态(推荐生产方案)
当需要每秒级活跃连接、实时 P95、节点健康状态等维度时,vts 模块比日志更准、更及时:
- 编译 Nginx 时加入
nginx-module-vts,或使用预编译支持 vts 的 OpenResty - 在 http 块中启用:
vhost_traffic_status_zone;
location /status { vhost_traffic_status_display; vhost_traffic_status_display_format html; } - 访问
/status?format=json可看到每个 upstream 的responseMsec(毫秒)、inBytes、outBytes、active等字段 - 配置 nginx-prometheus-exporter 指向该 JSON 接口:
--nginx.scrape-uri=http://127.0.0.1/status?format=json,它会自动转换为:nginx_upstream_server_response_msec{upstream="api",server="10.20.30.41:8080"} - 优势:无日志 IO 压力、不依赖磁盘轮转、天然支持 per-server 分位数(vts 内置 P95/P99 计算)
用 OpenResty + Lua 自定义打点(推荐高精度/低延迟场景)
当你要控制采样逻辑(如只统计 200 成功请求)、做滑动窗口均值、或透传 trace_id 对齐链路追踪时,Lua 是唯一灵活选择:
- 在 location 中用
log_by_lua_block读取ngx.var.upstream_response_time,转数值后上报到共享字典或直接推送到 /metrics - 配合
prometheus.lua库定义带标签的直方图:hist:observe(tonumber(ngx.var.upstream_response_time) or 0, ngx.var.backend_name) - 暴露
/metrics端点,Prometheus 抓取即可获得:nginx_upstream_response_time_seconds_sum{upstream="svc-order"}nginx_upstream_response_time_seconds_count{upstream="svc-order"} - 好处:完全绕过日志落盘,毫秒级延迟感知;可结合
$upstream_header_time和$upstream_connect_time拆解建连、首字节、体传输各阶段耗时
查 P95/P99 耗时的 PromQL 写法
无论哪种采集方式,最终分析都靠 PromQL。以下通用写法可直接复用:
- P95 响应耗时(单位秒):
histogram_quantile(0.95, sum(rate(nginx_upstream_response_time_seconds_bucket[1h])) by (le, upstream)) - 对比同一服务不同节点的长尾:
histogram_quantile(0.99, sum(rate(nginx_upstream_response_time_seconds_bucket{upstream=~"svc-user"}[30m])) by (le, server)) - 识别慢节点突增(过去 5 分钟 P95 > 1 秒):
histogram_quantile(0.95, sum(rate(nginx_upstream_response_time_seconds_bucket[5m])) by (le, server)) > 1











