Que fait distributed-tracing ?
Implémenter le tracing distribué avec Jaeger et Tempo pour suivre les requêtes entre microservices et identifier les goulots d'étranglement de performance. À utiliser lors du débogage de microservices, de l'analyse des flux de requêtes ou de la mise en place d'une observabilité pour des systèmes distribués.
Aperçu
Cette compétence configure et utilise le tracing distribué pour visualiser le flux des requêtes à travers les microservices. Elle prend en charge Jaeger et Grafana Tempo comme backends de tracing.
Prérequis
- Docker ou Podman pour exécuter les services de tracing
curlouwgetpour tester les endpoints- (Optionnel) OpenTelemetry Collector configuré
Configuration
Backend Jaeger
docker run -d --name jaeger \
-e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \
-p 5775:5775/udp \
-p 6831:6831/udp \
-p 6832:6832/udp \
-p 5778:5778 \
-p 16686:16686 \
-p 14250:14250 \
-p 14268:14268 \
-p 14269:14269 \
-p 9411:9411 \
jaegertracing/all-in-one:latest
Backend Tempo
docker run -d --name tempo \
-p 3200:3200 \
-p 4317:4317 \
-p 4318:4318 \
-v ./tempo-config.yaml:/etc/tempo.yaml \
grafana/tempo:latest -config.file=/etc/tempo.yaml
Exemple de tempo-config.yaml :
server:
http_listen_port: 3200
distributor:
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
storage:
trace:
backend: local
local:
path: /tmp/tempo
Instrumentation d'un service (OpenTelemetry)
Go
package main
import (
"context"
"log"
"net/http"
"time"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
"go.opentelemetry.io/otel/sdk/resource"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.17.0"
"go.opentelemetry.io/otel/trace"
)
func main() {
exporter, err := otlptrace.New(
context.Background(),
otlptracegrpc.NewClient(
otlptracegrpc.WithInsecure(),
otlptracegrpc.WithEndpoint("localhost:4317"),
),
)
if err != nil {
log.Fatal(err)
}
tp := sdktrace.NewTracerProvider(
sdktrace.WithBatcher(exporter),
sdktrace.WithResource(resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceNameKey.String("mon-service"),
)),
)
otel.SetTracerProvider(tp)
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
tracer := otel.Tracer("mon-service")
ctx, span := tracer.Start(r.Context(), "requete-racine")
defer span.End()
span.SetAttributes(attribute.String("http.method", r.Method))
// Simuler un travail
time.Sleep(50 * time.Millisecond)
w.WriteHeader(http.StatusOK)
})
log.Fatal(http.ListenAndServe(":8080", nil))
}
Python
from opentelemetry import trace
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.sdk.resources import SERVICE_NAME, Resource
resource = Resource(attributes={
SERVICE_NAME: "mon-service"
})
exporter = OTLPSpanExporter(endpoint="localhost:4317", insecure=True)
processor = BatchSpanProcessor(exporter)
provider = TracerProvider(resource=resource, active_span_processor=processor)
trace.set_tracer_provider(provider)
tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("requete-racine") as span:
span.set_attribute("http.method", "GET")
# Traitement simulé
Node.js
const { NodeTracerProvider } = require('@opentelemetry/sdk-trace-node');
const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-grpc');
const { BatchSpanProcessor } = require('@opentelemetry/sdk-trace-base');
const { Resource } = require('@opentelemetry/resources');
const { SemanticResourceAttributes } = require('@opentelemetry/semantic-conventions');
const provider = new NodeTracerProvider({
resource: new Resource({
[SemanticResourceAttributes.SERVICE_NAME]: 'mon-service',
}),
});
const exporter = new OTLPTraceExporter({
url: 'http://localhost:4317',
});
provider.addSpanProcessor(new BatchSpanProcessor(exporter));
provider.register();
const tracer = require('@opentelemetry/api').trace.getTracer('mon-service');
const span = tracer.startSpan('requete-racine');
span.setAttribute('http.method', 'GET');
// Travail simulé
span.end();
Vérification de l'envoi des traces
# Jaeger
curl http://localhost:16686/search?service=mon-service
# Tempo (requête TraceQL)
curl 'http://localhost:3200/api/search?q={resource.service.name="mon-service"}'
Dépannage
- Aucune trace reçue : Vérifiez que le collecteur OpenTelémétrie est en cours d'exécution et accessible.
- Échec de connexion : Vérifiez les variables d'environnement
OTEL_EXPORTER_OTLP_ENDPOINTouJAEGER_AGENT_HOST. - Échantillonnage des traces : Par défaut, toutes les traces ne sont pas échantillonnées. Ajustez le taux d'échantillonnage avec
OTEL_TRACES_SAMPLERou l'optionsamplercorrespondante.