跳到主要内容
版本:3.9.x

配置分布式追踪

分布式追踪展示请求如何经过 API7 网关与后端服务,可用于定位延迟和故障。API7 网关使用 opentelemetry 插件创建 Span,并将其导出到 OpenTelemetry Collector 或兼容可观测性后端等 OTLP/HTTP 端点。

本指南将配置一个用于评估的本地 Jaeger 实例,在全局启用追踪,并把导出的 Trace 与访问日志关联起来。

工作原理

opentelemetry 插件使用两层配置:

  • 插件元数据为网关组配置 Collector 端点、请求超时、资源属性、自定义请求头、批量 Span 处理器和 Trace ID 来源。
  • 插件配置选择采样策略并添加 Span 属性。你可以把插件应用到路由、服务或全局规则。

插件必须先配置元数据,才能创建并导出 Span。

前置条件

  • API7 网关部署正在运行,且至少有一个在线数据面。
  • 已安装 Docker,用于运行本地评估所需的 Jaeger。
  • 已将控制台令牌赋值给 API_KEY 环境变量。
  • 如果使用 ADC,请先安装并配置 ADC,包括 ADC_BACKENDADC_SERVERADC_TOKENADC_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 与访问日志。

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
}'

如果 Collector 要求身份认证,请在 collector.request_headers 下配置请求头。所有元数据字段和默认值请参阅插件元数据参考

在全局启用追踪

创建示例服务和路由,再通过全局规则应用 opentelemetry。该规则会追踪网关组中所有路由的请求。如果只需要追踪特定流量,请在个别路由或服务上配置插件。

示例使用固定 ID tracing-demoopentelemetry。应用配置前,请确认这些 ID 尚未使用,或在所有配置中一致地替换它们。

创建带上游的服务:

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"]
}
}
}'

additional_attributes 中的值是 APISIX 变量,例如 request_uriroute_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。

将以下配置添加到数据面的 conf/config.yaml

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

重新加载或重启数据面,使变更生效。

数据面就绪后,再发送一个请求:

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-loggerkafka-logger 等日志插件的 log_format 字段。

下一步