Begriff
Tracing (Distributed Tracing)
Warum wichtig?
Dieser Begriff ist ein Knoten im SengakujiWorks-Wissensnetz. Nutze Level 0 für die erste Einordnung, Level 1 für Praxis, Level 2 für technische Struktur und Level 3 für Grenzen, Fallstricke und Expertenkontext.
Deine App besteht aus 100 Microservices. User meldet: "Es ist langsam!" Wo? In Service A? Datenbank B? Oder im Netzwerk dazwischen? Mit Logs findest du das nie. Tracing verfolgt einen einzelnen Request auf seiner Reise durch alle Services. Jeder Service fügt einen Balken ("Span") hinzu: "Ich habe von 10:00 bis 10:01 gebraucht". Am Ende hast du ein Wasserfall-Diagramm (Gantt Chart), das genau zeigt, wer der Flaschenhals ist.
Merksatz: Eine Methode zur Verfolgung und Visualisierung eines Transaktionsflusses durch verteilte Systeme, um Latenzprobleme und Abhängigkeiten zu analysieren.
Tools: Jaeger, Zipkin, Tempo.
Du siehst einen Trace mit einer ID (trace-id: abc).
Darunter eine Liste von Spans:
Frontend: /checkout(200ms)Auth Service: Verify Token(50ms)Payment Service: Charge(150ms) -> Langsam! (ROT)Database: INSERT(140ms) -> Aha, die DB ist schuld!
1. Span Context & Propagation
Wie weiß der Payment Service, dass er zu Trace abc gehört?
Das Frontend muss die ID mitschicken.
Im HTTP Header: traceparent: 00-abc....
Der Payment Service liest den Header ("Extract"), erstellt einen Child Span, und gibt die ID weiter an die DB ("Inject").
Wenn ein Service in der Kette Tracing nicht unterstützt ("Black Hole"), bricht der Trace ab. Kontext geht verloren.
2. Overhead & Sampling
Tracing kostet Performance (CPU, Netzwerk, Storage). Jeder Request erzeugt kB an Daten. Bei Google Scale (Milliarden Requests) ist das Petabytes am Tag. Lösung: Sampling. "Speichere nur jeden 1000. Trace". (Probabilistic Sampling). Das reicht für Statistiken ("P99 Latenz"), aber beim Debuggen eines spezifischen Users ("Mein Request ging gerade schief") hast du Pech, wenn er weggeworfen wurde. Adaptive Sampling versucht, nur "interessante" Traces (Fehler, Langsam) zu behalten.
3. Asynchrones Tracing (Kafka)
Tracing ist einfach bei HTTP (Synchron).
Was ist bei Kafka/RabbitMQ?
Service A wirft Nachricht in Queue. Service B liest sie 5 Minuten später.
Ist das ein Trace?
Ja! Die Trace ID muss in den Message Headers (kafka_header) mitreisen.
Jaeger zeigt dann eine Lücke ("Consumer Lag") als Zeitbalken an.
Vergessen viele Entwickler zu implementieren.
W3C Trace Context Standard
Früher kochte jedes Tool (Jaeger, Zipkin, Datadog) bei Tracing sein eigenes Süppchen. Der Header für die Trace-ID war mal X-B3-TraceId, mal X-Datadog-Trace-Id. Brach der Traffic von AWS zu Google Cloud, ging der Trace verloren.
Heute ist der W3C Trace Context ein verbindlicher Webstandard (HTTP).
Der Standard definiert exakt zwei Header: traceparent (enthält Version, Trace-ID, Parent-Span-ID und Sampling-Flags) und tracestate (Vendor-spezifische Metadaten, die unberührt durchgeschleift werden). Wenn heute ein Nginx-Ingress einen Traffic empfängt, generiert er automatisch einen korrekten W3C-Header und zwingt das nachgelagerte NodeJS-App-Stack sofort in diese eine, globale Trace-Einheit.
Head-Based vs. Tail-Based Sampling
Wenn man nur 1% aller Traces speichert, um Storage-Kosten einzusparen, gibt es zwei Methoden:
- Head-Based Sampling: Direkt am Ingress (Load Balancer) wird gewürfelt: "Spiele ich mit oder nicht?". Der Ingress setzt das "Sampled"-Flag im Header. Alle Microservices wissen sofort: "Ah, den werfen wir weg." Problem: Wenn der Request erst 5 Minuten später tief im Payment-Service crashed, wurde der Trace schon am Eingangsbereich gelöscht!
- Tail-Based Sampling: Das absolute High-End-Setup. Alle Services schicken jeden Span (100%) asynchron an einen OpenTelemetry Collector. Der Collector ist ein fetter In-Memory-Puffer. Er sammelt den Transaktions-Trace solange, bis der Root-Request stirbt oder succeedet. Erst dann am "Schwanz" (Tail) betrachtet er den Graphen: "War ein Fehler drin? War er sehr langsam?" Ja? Puffer auf Disk sichern! Nein? Löschen.
OpenTelemetry (OTel) Collector Pipelines
Der OTel Collector ist das Schweizer Taschenmesser der Observability. Er entkoppelt deine App vom Storage-Vendor (Du bist nicht mehr an Datadog gebunden).
Er besteht aus Receivers (Nimmt OTLP, Zipkin, Prometheus entgegen), Processors (Entfernt z.B. Kreditkarten-Daten per Regex aus Spans, batcht sie zusammen) und Exporters (Wandelt das Format um und pusht es zu Jaeger oder Honeycomb gleichzeitig). Das "Instrumentation" deiner Services muss also nie wieder geändert werden, wenn ihr euren Observability-Provider wechselt.
Quick-Check
Log Correlation?
Der Heilige Gral. Im Log steht die Trace ID ([INFO] trace_id=abc). Im Trace Tool klickst du auf "Show Logs" und siehst genau die Logs von diesem Request. Ohne ID suchst du die Nadel im Heuhaufen.Root Span?
Der allererste Span (meist Ingress oder Frontend), der die Trace ID generiert hat. Er hat keinen Parent. Alle anderen sind Kinder oder Enkel.Auto-Instrumentation?
Java/Python Agents können JDBC (Datenbank) Aufrufe automatisch tracen ("SELECT * FROM..."), ohne dass du Code ändern musst. Sie wrappen den Driver.