配置分布式追踪
分布式追踪展示请求如何经过 API7 网关与后端服务,可用于定位延迟和故障。API7 网关使用 opentelemetry 插件创建 Span,并将其导出到 OpenTelemetry Collector 或兼容可观测性后端等 OTLP/HTTP 端点。
本指南将配置一个用于评估的本地 Jaeger 实例,在全局启用追踪,并把导出的 Trace 与访问日志关联起来。
工作原理
opentelemetry 插件使用两层配置:
- 插件元数据为网关组配置 Collector 端点、请求超时、资源属性、自定义请求头、批量 Span 处理器和 Trace ID 来源。
- 插件配置选择采样策略并添加 Span 属性。你可以把插件应 用到路由、服务或全局规则。
插件必须先配置元数据,才能创建并导出 Span。
前置条件
- API7 网关部署正在运行,且至少有一个在线数据面。
- 已安装 Docker,用于运行本地评估所需的 Jaeger。
- 已将控制台 Token赋值给
API_KEY环境变量。 - 如果使用 ADC,请先安装并配置 ADC,包括
ADC_BACKEND、ADC_SERVER、ADC_TOKEN和ADC_GATEWAY_GROUP环境变量。
启动 Jaeger
本地示例假设数据面在 Docker 中运行。对于其它部署方式,请使用数据面可以访问的 OTLP/HTTP 端点,跳过本节的 Docker 命令,并在配置插件元数据时替换成该端点的地址。
创建 Docker 网络并把数据面容器接入该网络。将 <data-plane-container> 替换为容器名称:
docker network create gateway-tracing-net
docker network connect gateway-tracing-net <data-plane-container>
在同一网络中启动固定版本的 Jaeger。该镜像通过 4318 端口接收 OTLP Trace,并通过 16686 端口提供 Jaeger UI:
docker run -d --name jaeger \
--network gateway-tracing-net \
-p 127.0.0.1:16686:16686 \
cr.jaegertracing.io/jaegertracing/jaeger:2.20.0
等待 Jaeger UI 可用:
until curl -fsS "http://127.0.0.1:16686/" > /dev/null; do
sleep 1
done
该 Jaeger 实例使用临时的内存存储,且未启用身份认证或 TLS。生产环境应使用带持久化存储的安全 Collector 或可观测性后端。如果已有合适的 OTLP/HTTP 端点,请跳过本节,并在下文替换成该端点的地址。
配置 Collector 端点
配置插件元数据,把 Span 发送到 Jaeger,并将 Trace ID 和 Span ID 暴露为 NGINX 变量。这些变量将在后续步骤中用于关联 Trace 与访问日志。
- Admin API
- ADC
curl -k "https://localhost:7443/apisix/admin/plugin_metadata/opentelemetry?gateway_group_id={gateway_group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"resource": {
"service.name": "api7-gateway",
"deployment.environment": "development"
},
"collector": {
"address": "jaeger:4318",
"request_timeout": 3
},
"set_ngx_var": true
}'
将插件元数据添加到现有 ADC 配置中,使其它插件元数据保持在期望状态:
plugin_metadata:
opentelemetry:
resource:
service.name: api7-gateway
deployment.environment: development
collector:
address: "jaeger:4318"
request_timeout: 3
set_ngx_var: true
预览插件元数据协调结果,确认其中没有非预期的更新或删除:
adc diff -f adc.yaml --include-resource-type plugin_metadata
同步已审查的配置:
adc sync -f adc.yaml --include-resource-type plugin_metadata
如果 Collector 要求身份认证,请在 collector.request_headers 下配置请求头。所有元数据字段和默认值请参阅插件元数据参考。
在全局启用追踪
创建示例服务和路由,再通过全局规则应用 opentelemetry。该规则会追踪网关组中所有路由的请求。如果只需要追踪特定流量,请在个别路由或服务上配置插件。
示例使用固定 ID tracing-demo 和 opentelemetry。应用配置前,请确认这些 ID 尚未使用,或在所有配置中一致地替换它们。
- Admin API
- ADC
创建带上游的服务:
curl -k "https://localhost:7443/apisix/admin/services/tracing-demo?gateway_group_id={gateway_group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "tracing-demo",
"upstream": {
"type": "roundrobin",
"scheme": "http",
"nodes": [
{ "host": "httpbin.org", "port": 80, "weight": 1 }
]
}
}'
在服务下创建路由:
curl -k "https://localhost:7443/apisix/admin/routes/tracing-demo?gateway_group_id={gateway_group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "tracing-demo",
"service_id": "tracing-demo",
"paths": ["/anything"]
}'
使用全局规则启用追踪:
curl -k "https://localhost:7443/apisix/admin/global_rules/opentelemetry?gateway_group_id={gateway_group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"plugins": {
"opentelemetry": {
"sampler": {
"name": "trace_id_ratio",
"options": { "fraction": 1.0 }
},
"additional_attributes": ["request_uri"]
}
}
}'
将服务、路由和全局规则添加到现有 ADC 配置中,使其它服务和全局规则保持在期望状态:
services:
- name: tracing-demo
routes:
- name: tracing-demo
uris:
- /anything
upstream:
type: roundrobin
nodes:
- host: httpbin.org
port: 80
weight: 1
global_rules:
opentelemetry:
sampler:
name: trace_id_ratio
options:
fraction: 1.0
additional_attributes:
- request_uri
预览协调结果,确认其中没有非预期的更新或删除:
adc diff -f adc.yaml \
--include-resource-type service \
--include-resource-type global_rule
同步已审查的配置。资源类型过滤器也会让插件元数据保持不变:
adc sync -f adc.yaml \
--include-resource-type service \
--include-resource-type global_rule
additional_attributes 中的值是 APISIX 变量,例如 request_uri 或 route_name。插件会自动添加常用属性,包括匹配的路由、路由名称、状态码和响应来源。
选择采样策略
| 策略 | 适用场景 |
|---|---|
always_on | 开发、预发布或低流量环境,需要追踪每个请求。 |
trace_id_ratio | 生产流量,使用 0.01 等采样比例控制 Collector 负载和存储用量。共享同一 Trace ID 的服务会得出确定一致的决策。 |
parent_base | 由上游服务或 Service Mesh 决定是否采样。网关遵循父级决策;不存在父级 Span 时使用根采样器。 |
always_off | 默认值。用于保留已挂载的插件而不发送 Span。 |
常见的生产策略是使用 parent_base,并配置低比例的根采样器。这样既能保持已有分布式 Trace 完整,又能以可控比例采样新的根 Trace:
{
"sampler": {
"name": "parent_base",
"options": {
"root": {
"name": "trace_id_ratio",
"options": { "fraction": 0.01 }
}
}
}
}
所有插件参数请参阅 opentelemetry 插件参考。
验证 Trace 导出
通过网关发送请求:
curl -i "http://127.0.0.1:9080/anything"
等待异步导出的 Trace 可用:
trace_ready=false
for attempt in $(seq 1 20); do
if curl -fsS \
"http://127.0.0.1:16686/api/traces?service=api7-gateway&limit=10&lookback=1h" | \
grep -q '"traceID"'; then
trace_ready=true
break
fi
sleep 1
done
[ "$trace_ready" = true ]
打开 http://127.0.0.1:16686 的 Jaeger UI,搜索 api7-gateway 服务。Trace 应包含名为 GET /anything 的 Span,并带有状态码、路由名称、响应来源和请求 URI 等属性。
将 Trace 与访问日志关联
把 Trace ID 和 Span ID 变量添加到访问日志格式中,从而可以定位与某条日志记录关联的 Trace。
- 主机或 Docker
- Kubernetes
将以下配置添加到数据面的 conf/config.yaml:
nginx_config:
http:
enable_access_log: true
access_log_format: '{"time":"$time_iso8601","trace_id":"$opentelemetry_trace_id","span_id":"$opentelemetry_span_id","status":$status,"request":"$request"}'
access_log_format_escape: json
重新加载或重启数据面,使变更生效。
将以下 values 添加到数据面 Helm 配置中:
logs:
enableAccessLog: true
accessLogFormat: '{"time":"$time_iso8601","trace_id":"$opentelemetry_trace_id","span_id":"$opentelemetry_span_id","status":$status,"request":"$request"}'
accessLogFormatEscape: json
应用这些 values。请将占位符替换为 Helm release 名称和命名空间:
helm upgrade <release-name> api7/gateway \
--version "~3.10.0" \
--namespace <namespace> \
-f values.yaml
数据面就绪后,再发送一个请求:
curl -i "http://127.0.0.1:9080/anything"
访问日志应包含非空的 Trace ID 和 Span ID,类似以下内容:
{
"time": "2026-09-16T10:30:00+00:00",
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
"span_id": "00f067aa0ba902b7",
"status": 200,
"request": "GET /anything HTTP/1.1"
}
相同变量也可用于 http-logger 和 kafka-logger 等日志插件的 log_format 字段。
下一步
- 阅读监控指标,把 Trace 与 Prometheus 指标和延迟仪表盘关联起来。
- 阅读配置集中式日志记录,把带 Trace 关联信息的访问日志发送到日志后端。
- 查阅
opentelemetry插件参考,了解全部插件和元数据字段。