深色模式
Trace 与指标关联
摘要:看到 P99 延迟飙升时,最想问的是"到底是哪几个请求慢"。Exemplar 就是回答这个问题的钥匙——它把 trace_id 挂在直方图样本上,让你从指标的曲线上一个点直接跳到那条链路。本文给出 Exemplar 的开启、验证与下钻分析全流程。
适用环境
bash
# Prometheus 需开启 exemplar 存储(启动时加 --enable-feature=exemplar-storage)
curl -s http://127.0.0.1:9090/api/v1/status/flags | grep -o 'exemplar-storage'
# 后端链路系统在线
curl -fsS http://127.0.0.1:3200/ready
# 应用已暴露 OTel 直方图指标
curl -s http://127.0.0.1:8080/metrics | grep -c 'duration_seconds_bucket'1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
操作步骤
1. 开启 Prometheus 的 exemplar 存储
bash
prometheus \
--config.file=/etc/prometheus/prometheus.yml \
--enable-feature=exemplar-storage \
--storage.tsdb.path=/data/prometheus1
2
3
4
2
3
4
bash
# systemd 方式:修改 ExecStart 后重启
sudo systemctl edit prometheus # 增加 ExecStart 参数
sudo systemctl restart prometheus1
2
3
2
3
2. 应用侧产生带 exemplar 的直方图
python
from opentelemetry.metrics import get_meter_provider, set_meter_provider
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader
from opentelemetry.exporter.prometheus import PrometheusMetricReader
from prometheus_client import start_http_server
start_http_server(port=8080, addr="0.0.0.0") # 暴露 /metrics
set_meter_provider(MeterProvider(metric_readers=[PrometheusMetricReader()]))
meter = get_meter_provider().get_meter("demo")
histogram = meter.create_histogram(
name="http_server_request_duration_seconds",
unit="s",
description="HTTP 请求耗时",
)
# 记录时把当前 span context 传进去,SDK 会自动写入 exemplar
histogram.record(duration, {"http.route": "/api/order"},
context=trace.get_current_span().get_span_context())1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
3. 确认指标里带上了 trace_id
bash
curl -s http://127.0.0.1:8080/metrics | grep 'duration_seconds_bucket' | grep 'trace_id' | head -3
# 形如:http_server_request_duration_seconds_bucket{...le="0.5"} 3.0 # {trace_id="4bf92f..."} 0.421
2
2
4. 在 Grafana 里配置下钻
yaml
# 数据源里给 Prometheus 配置 exemplar 跳转,或直接在面板用 data link
# Panel JSON 片段思路
fieldConfig:
defaults:
links:
- title: "查看该请求的链路"
url: "http://tempo.example.com/trace/${__data.fields.trace_id}"1
2
3
4
5
6
7
2
3
4
5
6
7
5. 从指标下钻的完整流程
bash
# 1) 查询 P99,找到异常时间点
curl -s 'http://127.0.0.1:9090/api/v1/query' --data-urlencode \
'query=histogram_quantile(0.99, sum(rate(http_server_request_duration_seconds_bucket[5m])) by (le))'
# 2) 查该时段的 exemplar,拿到 trace_id
curl -s 'http://127.0.0.1:9090/api/v1/query_exemplars' --data-urlencode \
'query=http_server_request_duration_seconds_bucket' --data-urlencode 'start=<起>' --data-urlencode 'end=<止>'
# 3) 用 trace_id 打开链路详情
curl -s "http://127.0.0.1:3200/api/traces/<trace_id>" | head -c 3001
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
6. 反向关联:从 trace 找同类指标
bash
# 用 span 属性里的 service.name + http.route 拼出 PromQL
curl -s 'http://127.0.0.1:9090/api/v1/query' --data-urlencode \
'query=sum(rate(http_server_request_duration_seconds_count{http_route="/api/order"}[5m]))'1
2
3
2
3
验证
bash
# 1) Prometheus 已开启 exemplar 特性
curl -s http://127.0.0.1:9090/api/v1/status/flags | python3 -c \
"import sys,json;print(json.load(sys.stdin)['data'].get('enable-feature',''))"
# 2) 能查到 exemplar 数据
curl -s 'http://127.0.0.1:9090/api/v1/query_exemplars' \
--data-urlencode 'query=http_server_request_duration_seconds_bucket' | head -c 300
# 3) 应用指标端点里能看到 trace_id 标注
curl -s http://127.0.0.1:8080/metrics | grep -o 'trace_id="[a-f0-9]\{32\}"' | head -2
# 4) Grafana 面板上点击 exemplar 点能跳转到链路页面(人工确认一次)1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
常见坑
WARNING
Prometheus 没加 --enable-feature=exemplar-storage 时,exemplar 会被静默丢弃,指标一切正常但就是点不出链路——这是最常见的"配了却没生效"。
WARNING
只有直方图(histogram)类型指标支持 exemplar。用 counter 或 gauge 记录耗时,永远无法下钻到具体请求,请把耗时类指标一律改为 histogram。
DANGER
Exemplar 里若携带了未脱敏的用户标识,等于把敏感数据写进了长期保留的指标存储。开启前请确认 trace 属性已脱敏,并在 Collector 侧配置属性过滤。