Steuern Sie Ihre Dienste mit OTEL, Jaeger und Prometheus

Lassen Sie uns eine wichtige Frage diskutieren: wie überwachen wir unsere Dienste, wenn etwas schief geht?

Auf der einen Seite haben wir Prometheus mit Warnmeldungen und Kibana für Dashboards und andere nützliche Funktionen. Wir wissen auch, wie wir Protokolle sammeln – der ELK-Stack ist unsere Lösung. Allerdings reichen einfache Protokollierungen nicht immer aus: Sie bieten keinen ganzheitlichen Blick auf die Reise einer Anfrage über das gesamte Ökosystem der Komponenten hinweg.

Weitere Informationen zu ELK finden Sie hier.

Aber was ist, wenn wir Anfragen visualisieren möchten? Was ist, wenn wir Anfragen korrelieren müssen, die zwischen Systemen unterwegs sind? Dies gilt sowohl für Mikrodienste als auch für Monolithen – es spielt keine Rolle, wie viele Dienste wir haben; wichtig ist, wie wir ihre Latenz verwalten.

In der Tat kann jede Benutzeranfrage eine ganze Reihe unabhängiger Dienste, Datenbanken, Nachrichtenwarteschlangen und externer APIs durchlaufen.

In einer so komplexen Umgebung wird es äußerst schwierig, genau zu bestimmen, wo Verzögerungen auftreten, zu identifizieren, welcher Teil der Kette als Leistungsengpass fungiert, und schnell die Ursache von Fehlern zu finden, wenn sie auftreten.

Um diesen Herausforderungen effektiv zu begegnen, benötigen wir ein zentrales, konsistentes System zur Erfassung von Telemetriedaten – Traces, Metriken und Protokollen. Hier kommen OpenTelemetry und Jaeger zur Rettung.

Schauen wir uns die Grundlagen an

Es gibt zwei Hauptbegriffe, die wir verstehen müssen:

Trace-ID

Eine Trace-ID ist ein 16-Byte-Identifikator, der oft als 32-stelliger hexadezimaler String dargestellt wird. Sie wird automatisch zu Beginn eines Traces generiert und bleibt über alle von einer bestimmten Anfrage erstellten Spans gleich. Dies erleichtert es, nachzuvollziehen, wie eine Anfrage durch verschiedene Dienste oder Komponenten in einem System läuft.

Span-ID

Jede einzelne Operation innerhalb eines Traces erhält ihre eigene Span-ID, die typischerweise ein zufällig generierter 64-Bit-Wert ist. Spans teilen sich die gleiche Trace-ID, aber jeder hat eine einzigartige Span-ID, sodass Sie genau bestimmen können, welcher Teil des Workflows durch jeden Span dargestellt wird (wie eine Datenbankabfrage oder einen Aufruf an einen anderen Mikrodienst).

Wie hängen sie zusammen?

Trace-ID und Span-IDergänzen sich. 

Wenn eine Anfrage initiiert wird, wird eine Trace-ID generiert und an alle beteiligten Dienste weitergegeben. Jeder Dienst erstellt wiederum einen Span mit einer einzigartigen Span-ID, die mit der Trace-ID verknüpft ist, sodass Sie den gesamten Lebenszyklus der Anfrage von Anfang bis Ende visualisieren können.

Okay, warum nicht einfach Jaeger verwenden? Warum brauchen wir OpenTelemetry (OTEL) und all seine Spezifikationen? Das ist eine großartige Frage! Lassen Sie uns das Schritt für Schritt aufschlüsseln.

Erfahren Sie mehr über Jaeger hier.

Zusammenfassung

  • Jaeger ist ein System zum Speichern und Visualisieren verteilter Spuren. Es sammelt, speichert, durchsucht und zeigt Daten an, die zeigen, wie Anfragen durch Ihre Dienste „reisen“.
  • OpenTelemetry (OTEL) ist ein Standard (und eine Sammlung von Bibliotheken) zum Sammeln von Telemetriedaten (Spuren, Metriken, Protokolle) aus Ihren Anwendungen und Ihrer Infrastruktur. Es ist nicht an ein einzelnes Visualisierungstool oder Backend gebunden.

Vereinfacht gesagt:

  • OTEL ist wie eine „universelle Sprache“ und eine Sammlung von Bibliotheken zum Sammeln von Telemetriedaten.
  • Jaeger ist ein Backend und eine Benutzeroberfläche zum Anzeigen und Analysieren verteilter Spuren.

Warum brauchen wir OTEL, wenn wir bereits Jaeger haben?

1. Ein einheitlicher Standard für die Sammlung

In der Vergangenheit gab es Projekte wie OpenTracing und OpenCensus. OpenTelemetry vereint diese Ansätze zur Sammlung von Metriken und Spuren in einem universellen Standard.

2. Einfache Integration

Sie schreiben Ihren Code in Go (oder einer anderen Sprache), fügen OTEL-Bibliotheken zum automatischen Injizieren von Interceptoren und Spans hinzu, und das war’s. Danach ist es egal, wohin Sie diese Daten senden möchten – Jaeger, Tempo, Zipkin, Datadog, ein benutzerdefiniertes Backend – OpenTelemetry kümmert sich um die Verkabelung. Sie wechseln einfach den Exporteur.

3. Nicht nur Spuren

OpenTelemetry deckt Spuren ab, aber es behandelt auch Metriken und Protokolle. Sie haben am Ende ein einziges Werkzeugset für all Ihre Telemetriebedürfnisse, nicht nur zum Tracing.

4. Jaeger als Backend

Jaeger ist eine ausgezeichnete Wahl, wenn Sie hauptsächlich an der Visualisierung von verteiltem Tracing interessiert sind. Aber es bietet standardmäßig keine plattformübergreifende Instrumentierung. OpenTelemetry hingegen gibt Ihnen eine standardisierte Möglichkeit, Daten zu sammeln, und dann entscheiden Sie, wohin Sie sie senden (einschließlich Jaeger).

In der Praxis arbeiten sie oft zusammen:

Ihre Anwendung verwendet OpenTelemetry → kommuniziert über das OTLP-Protokoll → geht zum OpenTelemetry Collector (HTTP oder grpc) → exportiert nach Jaeger zur Visualisierung.


Technischer Teil

Systemdesign (Ein bisschen)

Lassen Sie uns schnell ein paar Dienste skizzieren, die Folgendes tun:

  1. Kaufdienst – verarbeitet eine Zahlung und zeichnet sie in MongoDB auf
  2. CDC mit Debezium – hört auf Änderungen in der MongoDB-Tabelle und sendet sie an Kafka
  3. Kaufverarbeiter – konsumiert die Nachricht von Kafka und ruft den Auth-Dienst auf, um die user_id zur Validierung abzurufen
  4. Auth-Dienst – ein einfacher Benutzerdienst

Zusammenfassend:

  • 3 Go-Dienste
  • Kafka
  • CDC (Debezium)
  • MongoDB

Code-Teil

Fangen wir mit der Infrastruktur an. Um alles zu einem System zusammenzuführen, erstellen wir eine große Docker Compose-Datei. Wir beginnen mit der Einrichtung der Telemetrie.

Hinweis: Der gesamte Code ist über einen Link am Ende des Artikels verfügbar, einschließlich der Infrastruktur.

YAML

 

Wir werden auch den Collector konfigurieren – die Komponente, die Telemetrie sammelt.

Hier wählen wir gRPC für den Datentransfer, was bedeutet, dass die Kommunikation über HTTP/2 erfolgt:

YAML

 

Stellen Sie sicher, dass Sie alle Adressen nach Bedarf anpassen, und Sie sind mit der Grundkonfiguration fertig.

Wir wissen bereits, dass OpenTelemetry (OTEL) zwei Schlüsselkonzepte verwendet – Trace-ID und Span-ID – die helfen, Anfragen in verteilten Systemen zu verfolgen und zu überwachen.

Implementierung des Codes

Jetzt schauen wir uns an, wie wir das in Ihrem Go-Code zum Laufen bringen können. Wir benötigen die folgenden Importe:

Go

 

Dann fügen wir eine Funktion hinzu, um unseren Tracer in main() beim Start der Anwendung zu initialisieren:

Go

 

Mit dem eingerichteten Tracing müssen wir nur noch Spans im Code platzieren, um die Aufrufe zu verfolgen. Zum Beispiel, wenn wir Datenbankaufrufe messen wollen (da dies normalerweise der erste Ort ist, an dem wir nach Leistungsproblemen suchen), können wir etwas wie das hier schreiben:

Go

 

Wir haben das Tracing auf der Service-Ebene – großartig! Aber wir können sogar noch tiefer gehen und die Datenbankebene instrumentieren:

Go

 

Jetzt haben wir eine vollständige Sicht auf die Reise der Anfrage. Gehen Sie zur Jaeger-Benutzeroberfläche, fragen Sie die letzten 20 Traces unter auth-service ab, und Sie sehen alle Spans und wie sie an einem Ort verbunden sind.

Jetzt ist alles sichtbar. Wenn Sie es benötigen, können Sie die gesamte Abfrage in die Tags einfügen. Bedenken Sie jedoch, dass Sie Ihre Telemetrie nicht überladen sollten — fügen Sie Daten absichtlich hinzu. Ich zeige einfach, was möglich ist, aber die vollständige Abfrage auf diese Weise einzuschließen, ist etwas, das ich im Allgemeinen nicht empfehlen würde.

gRPC-Client-Server

Wenn Sie einen Trace sehen möchten, der sich über zwei gRPC-Dienste erstreckt, ist das ganz einfach. Alles, was Sie tun müssen, ist, die sofort einsatzbereiten Interceptor aus der Bibliothek hinzuzufügen. Zum Beispiel auf der Serverseite:

Go

 

Auf der Clientseite ist der Code ebenso kurz:

Go

 

Das ist alles! Stellen Sie sicher, dass Ihre Exporteure korrekt konfiguriert sind, und Sie werden eine einzige Trace-ID sehen, die über diese Dienste protokolliert wird, wenn der Client den Server aufruft.

Verarbeiten von CDC-Ereignissen und Tracing

Möchten Sie auch Ereignisse aus dem CDC verarbeiten? Ein einfacher Ansatz besteht darin, die Trace-ID in das Objekt einzubetten, das MongoDB speichert. Auf diese Weise ist die Trace-ID bereits Teil des Datensatzes, wenn Debezium die Änderung erfasst und an Kafka sendet.

Wenn Sie beispielsweise MongoDB verwenden, können Sie so etwas tun:

Go

 

Debezium nimmt dann dieses Objekt (einschließlich trace_id) auf und sendet es an Kafka. Auf der Consumer-Seite analysieren Sie einfach die eingehende Nachricht, extrahieren die trace_id und fügen sie in Ihren Tracing-Kontext ein:

Go

 

Go

 

Alternative: Verwendung von Kafka-Headern

Manchmal ist es einfacher, die Trace-ID in Kafka-Headern zu speichern, anstatt im Payload selbst. Für CDC-Workflows ist dies möglicherweise nicht standardmäßig verfügbar — Debezium kann einschränken, was zu Headern hinzugefügt wird. Aber wenn Sie die Produzenten-Seite kontrollieren (oder wenn Sie einen Standard-Kafka-Produzenten verwenden), können Sie etwas wie folgt mit Sarama tun:

Eine Trace-ID in Headern injizieren

Go

 

Eine Trace-ID auf der Verbraucherseite extrahieren

Go

 

Je nach Anwendungsfall und wie Ihre CDC-Pipeline eingerichtet ist, können Sie den Ansatz wählen, der am besten funktioniert:

  1. Die Trace-ID im Datenbankeintrag einbetten, damit sie natürlich über CDC fließt.
  2. Verwenden Sie Kafka-Header, wenn Sie mehr Kontrolle über die Produzenten-Seite haben oder wenn Sie vermeiden möchten, das Nachrichten-Payload aufzublähen.

So oder so können Sie Ihre Traces über mehrere Dienste hinweg konsistent halten — selbst wenn Ereignisse asynchron über Kafka und Debezium verarbeitet werden.

Fazit

Die Verwendung von OpenTelemetry und Jaeger liefert detaillierte Anfrage-Trace-Daten, die Ihnen helfen, herauszufinden, wo und warum Verzögerungen in verteilten Systemen auftreten.

Die Hinzufügung von Prometheus vervollständigt das Bild mit Metriken — wichtigen Indikatoren für Leistung und Stabilität. Zusammen bilden diese Werkzeuge einen umfassenden Observabilitäts-Stack, der schnellere Problemerkennung und -lösung, Leistungsoptimierung und die allgemeine Zuverlässigkeit des Systems ermöglicht.

Ich kann sagen, dass dieser Ansatz die Fehlersuche in einer Mikroservices-Umgebung erheblich beschleunigt und eines der ersten Dinge ist, die wir in unseren Projekten umsetzen.

Links

Source:
https://dzone.com/articles/control-services-otel-jaeger-prometheus