Jaeger & OpenTelemetry 链路追踪
链路追踪概念
用户请求
│ TraceID: abc123
▼
API Gateway (Span 1: 50ms)
│
├── User Service (Span 2: 10ms)
│ └── DB Query (Span 3: 5ms)
│
└── Order Service (Span 4: 30ms)
├── Inventory Service (Span 5: 8ms)
└── Payment Service (Span 6: 15ms)Jaeger 安装
bash
# 使用 Jaeger Operator
kubectl create namespace observability
kubectl apply -f https://github.com/jaegertracing/jaeger-operator/releases/download/v1.54.0/jaeger-operator.yaml -n observability
# 创建 Jaeger 实例
cat <<EOF | kubectl apply -f -
apiVersion: jaegertracing.io/v1
kind: Jaeger
metadata:
name: jaeger
namespace: observability
spec:
strategy: production
storage:
type: elasticsearch
options:
es:
server-urls: https://elasticsearch:9200
ingress:
enabled: true
hosts:
- jaeger.example.com
EOFOpenTelemetry Collector
yaml
# OTel Collector 配置
apiVersion: opentelemetry.io/v1alpha1
kind: OpenTelemetryCollector
metadata:
name: otel-collector
spec:
config: |
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
batch:
timeout: 1s
send_batch_size: 1024
memory_limiter:
limit_mib: 400
exporters:
jaeger:
endpoint: jaeger-collector:14250
tls:
insecure: true
prometheus:
endpoint: "0.0.0.0:8889"
logging:
loglevel: debug
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [jaeger]
metrics:
receivers: [otlp]
processors: [batch]
exporters: [prometheus]Go 应用集成
go
package main
import (
"context"
"net/http"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"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.21.0"
)
func initOTel(ctx context.Context) func() {
exporter, _ := otlptracegrpc.New(ctx,
otlptracegrpc.WithEndpoint("otel-collector:4317"),
otlptracegrpc.WithInsecure(),
)
res, _ := resource.New(ctx,
resource.WithAttributes(
semconv.ServiceName("my-service"),
semconv.ServiceVersion("v1.0.0"),
semconv.DeploymentEnvironment("production"),
),
)
tp := sdktrace.NewTracerProvider(
sdktrace.WithBatcher(exporter),
sdktrace.WithResource(res),
sdktrace.WithSampler(sdktrace.TraceIDRatioBased(0.1)), // 采样 10%
)
otel.SetTracerProvider(tp)
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(
propagation.TraceContext{},
propagation.Baggage{},
))
return func() { tp.Shutdown(ctx) }
}
func main() {
ctx := context.Background()
shutdown := initOTel(ctx)
defer shutdown()
tracer := otel.Tracer("my-service")
// 自动为 HTTP 处理器添加追踪
handler := otelhttp.NewHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
// 创建子 Span
ctx, span := tracer.Start(ctx, "处理业务逻辑")
defer span.End()
span.SetAttributes(
attribute.String("user.id", r.Header.Get("X-User-ID")),
)
// 调用下游服务(自动传播 TraceContext)
callDownstream(ctx)
w.WriteHeader(http.StatusOK)
}), "my-handler")
http.ListenAndServe(":8080", handler)
}