分布式链路追踪是微服务架构下服务治理和故障应急响应的核心手段。OpenTelemetry作为CNCF主导的可观测性标准,统一了Trace、Metrics、Logs三种信号采集协议。结合Jaeger后端存储和可视化分析,可实现跨服务的请求链路全貌追踪。本文从OpenTelemetry SDK集成、Jaeger部署、采样策略配置三个维度给出完整方案。
OpenTelemetry架构与核心概念
OpenTelemetry定义了Trace(追踪)、Span(跨度)、Context Propagation(上下文传播)三个核心概念。一次完整请求对应一个Trace,每个服务处理对应一个Span,Span之间存在父子关系形成调用树。TraceID和SpanID通过HTTP Header或gRPC Metadata在服务间传播。
/*
* OpenTelemetry核心概念:
* - Trace: 一次完整请求的唯一标识,128位TraceID
* - Span: 一次操作记录,包含操作名、开始结束时间、属性、事件、状态
* - Context: 在服务间传递TraceID和SpanID的载体
* W3C TraceContext格式: traceparent: 00-{trace-id}-{span-id}-01
*/
OpenTelemetry SDK集成(Java Spring Boot)
Spring Boot项目通过opentelemetry-spring-boot-starter自动注入Tracing能力,零代码侵入实现HTTP请求和数据库调用的自动埋点。
<!-- pom.xml 依赖 -->
<dependencies>
<!-- OpenTelemetry Spring Boot Starter -->
<dependency>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>opentelemetry-spring-boot-starter</artifactId>
<version>1.34.0</version>
</dependency>
<!-- OTLP Exporter: 发送Trace数据到Jaeger Collector -->
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-otlp</artifactId>
<version>1.34.0</version>
</dependency>
</dependencies>
<!-- application.yml -->
<!--
otel:
traces:
exporter: otlp
sampler:
type: parentbased_traceidratiobased
arg: 0.1 # 采样率10%
exporter:
otlp:
endpoint: http://jaeger-collector:4317
protocol: grpc
service:
name: order-service
resource:
attributes:
deployment.environment: production
host.name: ${hostname}
-->
parentbased_traceidratiobased采样策略基于TraceID按比例采样,父Span被采样则子Span一定被采样,保证调用链路完整性。10%采样率在生产环境中可在数据量和覆盖率之间取得平衡,关键业务接口可临时调高采样率。
// 自定义Span埋点:业务逻辑层手动埋点
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.StatusCode;
import io.opentelemetry.context.Scope;
@RestController
public class OrderController {
private final Tracer tracer;
private final OrderService orderService;
@PostMapping("/orders")
public Result<Order> createOrder(@RequestBody OrderRequest req) {
Span span = tracer.spanBuilder("createOrder")
.setAttribute("order.userId", req.getUserId())
.setAttribute("order.amount", req.getAmount())
.startSpan();
try (Scope scope = span.makeCurrent()) {
Order order = orderService.create(req);
span.setAttribute("order.id", order.getId());
return Result.success(order);
} catch (Exception e) {
span.recordException(e);
span.setStatus(StatusCode.ERROR, e.getMessage());
throw e;
} finally {
span.end();
}
}
}
手动埋点时务必使用try-with-resources确保Span在Scope退出后正确关闭。setAttribute记录业务维度信息,在Jaeger UI中可按属性值过滤和搜索Trace。recordException自动捕获异常堆栈并附加到Span事件。
Go语言OpenTelemetry集成
package main
import (
"context"
"log"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/sdk/resource"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.24.0"
)
func initTracer() (*sdktrace.TracerProvider, error) {
exporter, err := otlptracegrpc.New(context.Background(),
otlptracegrpc.WithEndpoint("jaeger-collector:4317"),
otlptracegrpc.WithInsecure(),
)
if err != nil {
return nil, err
}
res, _ := resource.New(context.Background(),
resource.WithAttributes(
semconv.ServiceName("payment-service"),
semconv.DeploymentEnvironment("production"),
),
)
tp := sdktrace.NewTracerProvider(
sdktrace.WithBatcher(exporter),
sdktrace.WithResource(res),
sdktrace.WithSampler(sdktrace.TraceIDRatioBased(0.1)),
)
otel.SetTracerProvider(tp)
otel.SetTextMapPropagator(propagation.TraceContext{})
return tp, nil
}
func processPayment(ctx context.Context, orderID string) error {
tracer := otel.Tracer("payment-service")
ctx, span := tracer.Start(ctx, "processPayment")
defer span.End()
span.SetAttributes(attribute.String("order.id", orderID))
// 业务逻辑...
return nil
}
Go通过otel.SetTextMapPropagator设置W3C TraceContext传播器,HTTP客户端和服务端中间件会自动提取和注入Trace Header。WithBatcher配置批量导出器,默认每5秒或每512条Span导出一次,减少网络请求开销。
Jaeger后端部署与存储配置
Jaeger支持内存、Elasticsearch、Cassandra、Kafka等多种存储后端。生产环境推荐Elasticsearch,兼顾查询性能和数据持久化。
# docker-compose.yml - Jaeger + Elasticsearch部署
version: '3.8'
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.12.0
environment:
- discovery.type=single-node
- xpack.security.enabled=false
- ES_JAVA_OPTS=-Xms2g -Xmx2g
volumes:
- es-data:/usr/share/elasticsearch/data
ports:
- "9200:9200"
jaeger-collector:
image: jaegertracing/jaeger-collector:1.55
environment:
- SPAN_STORAGE_TYPE=elasticsearch
- ES_SERVER_URLS=http://elasticsearch:9200
- ES_TAGS_AS_FIELDS_ALL=true
ports:
- "4317:4317" # OTLP gRPC
- "4318:4318" # OTLP HTTP
depends_on:
- elasticsearch
jaeger-query:
image: jaegertracing/jaeger-query:1.55
environment:
- SPAN_STORAGE_TYPE=elasticsearch
- ES_SERVER_URLS=http://elasticsearch:9200
ports:
- "16686:16686" # Jaeger UI
depends_on:
- elasticsearch
volumes:
es-data:
ES_TAGS_AS_FIELDS_ALL=true将Span属性索引为Elasticsearch字段而非嵌套对象,提升基于属性值的查询性能。Jaeger Collector接收OTLP协议数据并写入ES,Jaeger Query提供UI查询和API接口。Collector和Query分离部署便于独立扩展。
采样策略与性能优化
# 自定义采样策略:基于路径和错误率动态采样
# /etc/jaeger/sampling-strategies.json
{
"service_strategies": [
{
"service": "payment-service",
"type": "probabilistic",
"param": 1.0,
"operation_strategies": [
{
"operation": "/api/payments",
"type": "probabilistic",
"param": 1.0
},
{
"operation": "/api/payments/health",
"type": "probabilistic",
"param": 0.0
}
]
},
{
"service": "order-service",
"type": "ratelimiting",
"param": 100
}
],
"default_strategy": {
"type": "probabilistic",
"param": 0.05
}
}
支付服务100%采样确保所有支付链路可追溯,健康检查接口0%采样避免噪声数据。默认5%采样率控制非关键服务数据量。ratelimiting类型按每秒请求数限流采样,适合高QPS服务。采样策略通过Jaeger Collector的API动态下发,客户端定期拉取更新,无需重启服务。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/fen-bu-shi-lian-lu-zhui-zong-shi-zhan-opentelemetry-ji/