BLOG | NGINX

NGINX-Tutorial: So nutzen Sie OpenTelemetry Tracing zum Verständnis Ihrer Microservices

NGINX-Teil-von-F5-horiz-schwarz-Typ-RGB
Javier Evans Miniaturbild
Javier Evans
Veröffentlicht am 28. März 2023

Dieser Beitrag ist eines von vier Tutorials, die Ihnen helfen, Konzepte aus Microservices März 2023 in die Praxis umzusetzen: Beginnen Sie mit der Bereitstellung von Microservices :

 

Eine Microservices-Architektur bietet viele Vorteile, darunter eine größere Teamautonomie und mehr Flexibilität bei der Skalierung und Bereitstellung. Der Nachteil besteht darin, dass es umso schwieriger wird, einen klaren Überblick über den Gesamtbetrieb des Systems zu behalten, je mehr Dienste ein System umfasst (und eine Microservices-App kann Dutzende oder sogar Hunderte davon haben). Als Entwickler und Betreuer komplexer Softwaresysteme wissen wir, wie wichtig es ist, ein klares Bild zu haben. Beobachtbarkeit Mithilfe dieser Werkzeuge sind wir in der Lage, dieses Bild über zahlreiche Dienste und die unterstützende Infrastruktur hinweg aufzubauen.

In diesem Tutorial heben wir eine sehr wichtige Art der Beobachtbarkeit für Microservices-Apps hervor: das Tracing. Bevor wir beginnen, definieren wir einige Begriffe, die im Zusammenhang mit der Beobachtbarkeit häufig verwendet werden:

  • Beobachtbarkeit – Die Fähigkeit, den internen Zustand oder die Bedingung eines komplexen Systems (wie etwa einer Microservices-App) ausschließlich auf der Grundlage der Kenntnis seiner externen Ausgaben (wie etwa Spuren, Protokolle und Metriken) zu verstehen.
  • Überwachung – Die Fähigkeit, den Fortschritt oder Status eines Objekts über einen bestimmten Zeitraum zu beobachten und zu überprüfen. Sie können beispielsweise den Datenverkehr Ihrer App während der Spitzenzeiten überwachen und diese Informationen nutzen, um entsprechend zu skalieren.
  • Telemetrie – Das Erfassen von Messdaten, Spuren und Protokollen und deren Übertragung von ihrem Ursprungsort auf ein anderes System zur Speicherung und Analyse. Auch die Daten selbst.
  • Tracing/Traces – Ein Bericht über die Reise einer Anfrage oder Aktion durch alle Knoten eines verteilten Systems.
  • Span – Ein Datensatz innerhalb einer Ablaufverfolgung einer Operation und der zugehörigen Metadaten. Spuren bestehen aus vielen verschachtelten Bereichen.
  • Ereignisprotokollierung/Protokolle – Ein mit Zeitstempel versehener Textdatensatz mit Metadaten.
  • Metrik – Eine zur Laufzeit erfasste Messung. Beispielsweise die Speichermenge, die zu einem bestimmten Zeitpunkt von einer Anwendung verwendet wird.

Wir können all diese Konzepte nutzen, um Einblick in die Leistung unserer Microservices zu erhalten. Die Ablaufverfolgung ist ein besonders nützlicher Teil einer Beobachtungsstrategie, da sie einen „Gesamtüberblick“ darüber bietet, was bei einer Anforderung über mehrere, oft lose gekoppelte Komponenten hinweg geschieht. Darüber hinaus ist es eine besonders effektive Methode, Leistungsengpässe zu identifizieren.

In diesem Tutorial wird das Tracing-Toolkit von OpenTelemetry (OTel) verwendet, einem anbieterneutralen Open-Source-Standard zum Sammeln, Verarbeiten und Exportieren von Telemetriedaten, der immer beliebter wird. Nach dem Konzept von OTel zerlegt eine Ablaufverfolgung einen Datenfluss, der mehrere Dienste umfassen kann, in eine Reihe chronologisch angeordneter „Brocken“, die Ihnen das Verständnis erleichtern:

  • Alle Schritte, die in einem „Stück“ passiert sind
  • Wie lange all diese Schritte gedauert haben
  • Metadaten zu jedem Schritt

Wenn Sie mit OTel nicht vertraut sind, finden Sie unter „Was ist OpenTelemetry?“ eine ausführliche Einführung in den Standard und Hinweise zu seiner Implementierung.

Tutorialübersicht

In diesem Tutorial geht es vor allem um die Nachverfolgung der Vorgänge einer Microservices-App mit OTel. In den vier Herausforderungen dieses Tutorials erfahren Sie, wie Sie eine Anfrage durch Ihr System verfolgen und Fragen zu Ihren Microservices beantworten:

Diese Herausforderungen veranschaulichen unseren empfohlenen Prozess beim erstmaligen Einrichten der Ablaufverfolgung. Die Schritte sind:

  1. Verstehen Sie das System sowie den speziellen Vorgang, den Sie instrumentieren.
  2. Entscheiden Sie, was Sie vom laufenden System wissen müssen.
  3. Instrumentieren Sie das System „naiv“ – das heißt, verwenden Sie eine Standardkonfiguration, ohne zu versuchen, nicht benötigte Informationen auszusortieren oder benutzerdefinierte Datenpunkte zu erfassen – und beurteilen Sie, ob die Instrumentierung Ihnen bei der Beantwortung Ihrer Fragen hilft.
  4. Optimieren Sie die gemeldeten Informationen, damit Sie diese Fragen schneller beantworten können.

Notiz: Unsere Absicht in diesem Tutorial besteht darin, einige Kernkonzepte der Telemetrie zu veranschaulichen und nicht, die richtige Art und Weise zum Bereitstellen von Microservices in der Produktion zu zeigen. Obwohl eine echte „Microservices“-Architektur verwendet wird, gibt es einige wichtige Einschränkungen:

  • Das Tutorial verwendet kein Container-Orchestrierungsframework wie Kubernetes oder Nomad. Auf diese Weise können Sie sich mit den Konzepten von Microservices vertraut machen, ohne sich in den Einzelheiten eines bestimmten Frameworks zu verlieren. Die hier vorgestellten Muster sind auf ein System portierbar, auf dem eines dieser Frameworks läuft.
  • Die Dienste sind eher auf leichte Verständlichkeit als auf strenge Softwareentwicklung optimiert. Es geht darum, die Rolle eines Dienstes im System und seine Kommunikationsmuster zu betrachten, nicht die Einzelheiten des Codes. Weitere Informationen finden Sie in den README- Dateien der einzelnen Dienste.

Tutorial-Architektur und Telemetrieziele

Architektur und Benutzerfluss

Dieses Diagramm veranschaulicht die Gesamtarchitektur und den Datenfluss zwischen den Microservices und anderen Elementen, die im Tutorial verwendet werden.

Diagramm, das die im Tutorial verwendete Topologie zeigt, mit OpenTelemetry-Tracing eines Messaging-Systems mit zwei Microservices, NGINX und RabbitMQ

Die beiden Microservices sind:

  • Der Messenger- Dienst – Eine einfache Chat-API mit Nachrichtenspeicherfunktion
  • Der Benachrichtigungsdienst – Ein Listener, der Ereignisse auslöst, um Benutzer basierend auf ihren Präferenzen zu benachrichtigen.

Drei Teile der unterstützenden Infrastruktur sind:

  • NGINX Open Source – Ein Einstiegspunkt in den Messenger -Dienst und das Gesamtsystem
  • RabbitMQ – Ein beliebter Open-Source-Nachrichtenbroker, der es Diensten ermöglicht, asynchron zu kommunizieren
  • Jaeger – Ein Open-Source- End-to-End- Verteiltes Tracing-System zum Sammeln und Visualisieren von Telemetriedaten von Systemkomponenten, die diese Daten erzeugen.

Wenn wir OTel für einen Moment aus dem Bild lassen, können wir uns auf die Ereignisfolge konzentrieren, die wir verfolgen: was passiert, wenn ein Benutzer eine neue Chat-Nachricht sendet und der Empfänger darüber benachrichtigt wird.

Diagramm, das den Informationsfluss im im Tutorial verwendeten Nachrichtensystem zeigt

Der Ablauf gliedert sich folgendermaßen:

  1. Ein Benutzer sendet eine Nachricht an den Messenger -Dienst. Der NGINX-Reverse-Proxy fängt die Nachricht ab und leitet sie an eine von vielen Instanzen des Messenger- Dienstes weiter.
  2. Der Messenger- Dienst schreibt die neue Nachricht in seine Datenbank.
  3. Der Messenger- Dienst erzeugt ein Ereignis in einer RabbitMQ-Nachrichtenwarteschlange namens „chat_queue“, um anzuzeigen, dass eine Nachricht gesendet wurde. Die Veranstaltung ist allgemeiner Natur und hat kein spezifisches Ziel.
  4. Gleichzeitig:

    • 4a. Der Messenger- Dienst sendet eine Antwort an den Absender zurück und meldet, dass die Nachricht erfolgreich gesendet wurde.
    • 4b. Der Benachrichtigungsdienst bemerkt das neue Ereignis in der Chat-Warteschlange und nutzt es.
  5. Der Benachrichtigungsdienst prüft in seiner Datenbank die Benachrichtigungseinstellungen des Empfängers der neuen Nachricht.
  6. Der Benachrichtigungsdienst verwendet die bevorzugte Methode des Empfängers, um eine oder mehrere Benachrichtigungen zu senden (in diesem Tutorial stehen SMS und E-Mail zur Auswahl).

Telemetrieziele

Beim Einrichten der Telemetrieinstrumentierung ist es am besten, mit einer Reihe klarer definierterer Ziele für die Instrumentierung zu beginnen als „alles senden und auf Erkenntnisse hoffen“. Für dieses Tutorial verfolgen wir drei wichtige Telemetrieziele:

  1. Verstehen Sie alle Schritte, die eine Anfrage während des neuen Nachrichtenflusses durchläuft
  2. Sie können sicher sein, dass der Flow unter normalen Bedingungen innerhalb von fünf Sekunden durchgängig ausgeführt wird.
  3. Prüfen Sie, wie lange der Benachrichtigungsdienst braucht, um mit der Verarbeitung des vom Nachrichtendienst gesendeten Ereignisses zu beginnen (eine übermäßige Verzögerung kann bedeuten, dass der Benachrichtigungsdienst Probleme beim Lesen aus der Ereigniswarteschlange hat und sich Ereignisse stauen).

Beachten Sie, dass sich diese Ziele sowohl auf den technischen Betrieb des Systems als auch auf das Benutzererlebnis beziehen.

Voraussetzungen und Einrichtung des Tutorials

Voraussetzungen

Um das Tutorial in Ihrer eigenen Umgebung abzuschließen, benötigen Sie:

  • Eine Linux/Unix‑kompatible Umgebung

    Notiz: Die Aktivitäten in diesem Tutorial, bei denen es um die Verfolgung von NGINX geht, funktionieren nicht auf ARM-basierten Prozessoren, da das OpenTelemetry-Modul für NGINX nicht kompatibel ist. (Dazu gehören Linux aarch64-Architekturen und Apple-Maschinen mit dem M1- oder M2-Chip.) Die Aktivitäten, an denen die Messenger- und Benachrichtigungsdienste beteiligt sind, funktionieren auf allen Architekturen.

  • Grundlegende Kenntnisse der Linux-Befehlszeile, JavaScript und Bash (allerdings werden sämtliche Codes und Befehle bereitgestellt und erklärt, sodass Sie auch mit begrenzten Kenntnissen erfolgreich sein können)
  • Docker und Docker Compose
  • Node.js 19.x oder höher

    • Wir haben Version 19.x getestet, gehen aber davon aus, dass auch neuere Versionen von Node.js funktionieren.
    • Ausführliche Informationen zur Installation von Node.js finden Sie in der README-Datei im Repository des Messenger -Dienstes. Sie können auch asdf installieren, um genau dieselbe Node.js-Version zu erhalten, die im Tutorial verwendet wird.
  • curl (auf den meisten Systemen bereits installiert)
  • Die unter „Architektur und Benutzerfluss“ aufgeführten Technologien: Messenger und Notifier (Sie werden sie im nächsten Abschnitt herunterladen), NGINX Open Source , Jaeger und RabbitMQ .

Notiz: Das Tutorial verwendet das JavaScript SDK, da die Messenger- und Benachrichtigungsdienste in Node.js geschrieben sind. Sie können außerdem die automatische Instrumentierungsfunktion von OTel (auch Auto-Instrumentierung genannt) einrichten, damit Sie ein Gespür für die Art der von OTel verfügbaren Informationen bekommen. Das Tutorial erklärt alles, was Sie über das OTel Node.js SDK wissen müssen. Weitere Einzelheiten finden Sie jedoch in der OTel-Dokumentation .

Aufstellen

  1. Starten Sie eine Terminalsitzung.
  2. Erstellen Sie in Ihrem Home-Verzeichnis das Verzeichnis „Microservices-March“ und klonen Sie die GitHub-Repositorys für dieses Tutorial dort hinein. (Sie können auch einen anderen Verzeichnisnamen verwenden und die Anweisungen entsprechend anpassen.)

    Notiz: Im gesamten Tutorial wird die Eingabeaufforderung in der Linux-Befehlszeile weggelassen, um das Kopieren und Einfügen der Befehle in Ihr Terminal zu erleichtern. Die Tilde ( ~ ) steht für Ihr Home-Verzeichnis.

    mkdir ~/microservices-marchcd ~/microservices-march
    git-Klon https://github.com/microservices-march/messenger --branch mm23-metrics-start
    git-Klon https://github.com/microservices-march/notifier --branch mm23-metrics-start
    git-Klon https://github.com/microservices-march/platform --branch mm23-metrics-start
    

Herausforderung 1: Einrichten der grundlegenden OTel-Instrumentierung

In dieser Herausforderung starten Sie den Messenger- Dienst und konfigurieren die automatische OTel-Instrumentierung, um Telemetriedaten an die Konsole zu senden.

Starten Sie den Messenger-Dienst

  1. Wechseln Sie zum Plattform -Repository und starten Sie Docker Compose:

    cd ~/microservices-march/platformdocker zusammenstellen -d --build
    

    Dadurch werden RabbitMQ und Jaeger gestartet, die in nachfolgenden Herausforderungen verwendet werden.

    • Das Flag -d weist Docker Compose an, sich von Containern zu trennen, wenn diese gestartet wurden (andernfalls bleiben die Container an Ihr Terminal angeschlossen).
    • Das Flag --build weist Docker Compose an, beim Start alle Images neu zu erstellen. Dadurch wird sichergestellt, dass die von Ihnen ausgeführten Bilder bei allen möglichen Dateiänderungen auf dem neuesten Stand bleiben.
  2. Wechseln Sie in das App -Verzeichnis im Messenger -Repository und installieren Sie Node.js (Sie können bei Bedarf auch eine andere Methode verwenden):

    cd ~/microservices-march/messenger/appasdf installieren
    
  3. Installieren Sie Abhängigkeiten:

    npm installieren
    
  4. Starten Sie die PostgreSQL-Datenbank für den Messenger -Dienst:

    Docker komponieren -d
    
  5. Erstellen Sie das Datenbankschema und die Tabellen und fügen Sie einige Seed-Daten ein:

    npm führt Refresh-DB aus
    

Konfigurieren Sie die an die Konsole gesendete automatische OTel-Instrumentierung

Mit der automatischen OTel-Instrumentierung müssen Sie nichts in der Messenger -Codebasis ändern, um die Ablaufverfolgung einzurichten. Anstatt in den Anwendungscode selbst importiert zu werden, wird die gesamte Tracing-Konfiguration in einem Skript definiert, das zur Laufzeit in den Node.js-Prozess importiert wird.

Hier konfigurieren Sie die automatische Instrumentierung des Messenger- Dienstes mit dem grundlegendsten Ziel für Traces, der Konsole. In Herausforderung 2 ändern Sie die Konfiguration, um Traces an Jaeger als externen Collector zu senden.

  1. Installieren Sie die zentralen OTel Node.js-Pakete, während Sie weiterhin im App- Verzeichnis des Messenger -Repos arbeiten:

    npm installiere @opentelemetry/sdk-node@0.36.0 \
    @opentelemetry/auto-instrumentations-node@0.36.4
    

    Diese Bibliotheken bieten die folgende Funktionalität:

    • @opentelemetry/sdk-node – Generierung und Export von OTel-Daten
    • @opentelemetry/auto-instrumentations-node – Automatisches Setup mit Standardkonfiguration aller gängigen Node.js-Instrumentierungen

    Notiz: Es ist eine Eigenart von OTel, dass seine JavaScript-SDKs in sehr, sehr kleine Teile zerlegt sind. Sie werden also nur für das grundlegende Beispiel in diesem Tutorial ein paar weitere Pakete installieren. Um herauszufinden, welche Pakete Sie möglicherweise zum Ausführen von Instrumentierungsaufgaben benötigen, die über die in diesem Tutorial behandelten Aufgaben hinausgehen, lesen Sie die (sehr guten) OTel -Anleitungen für den Einstieg und sehen Sie sich das OTel- GitHub-Repository an.

  2. Erstellen Sie eine neue Datei namens tracing.mjs , die den Setup- und Konfigurationscode für die OTel-Verfolgung enthält:

    Berührungsverfolgung.mjs
    
  3. Öffnen Sie tracing.mjs in Ihrem bevorzugten Texteditor und fügen Sie diesen Code hinzu:

    //1
    importiere opentelemetry von "@opentelemetry/sdk-node";
    importiere { getNodeAutoInstrumentations } von "@opentelemetry/auto-instrumentations-node";
    
    //2
    const sdk = new opentelemetry.NodeSDK({
    traceExporter: new opentelemetry.tracing.ConsoleSpanExporter(),
    instrumentations: [getNodeAutoInstrumentations()],
    });
    
    //3
    sdk.start();
    

    Der Code bewirkt Folgendes:

    1. Importiert die erforderlichen Funktionen und Objekte aus dem OTel SDK.
    2. Erstellt eine neue Instanz des NodeSDK und konfiguriert sie wie folgt:

      • Senden Sie Spans an die Konsole ( ConsoleSpanExporter ).
      • Verwenden Sie den Auto-Instrumenter als Basis-Instrumentierungssatz. Diese Instrumentierung lädt alle gängigen Auto-Instrumentierungsbibliotheken. Im Tutorial sind folgende relevant:

        • @opentelemetry/instrumentation-pg für die Postgres-Datenbankbibliothek ( pg )
        • @opentelemetry/instrumentation-express für das Node.js Express-Framework
        • @opentelemetry/instrumentation-amqplib für die RabbitMQ-Bibliothek ( amqplib )
    3. Startet das SDK.
  4. Starten Sie den Messenger- Dienst und importieren Sie das Auto-Instrumentierungsskript, das Sie in Schritt 3 erstellt haben.

    node --import ./tracing.mjs index.mjs
    

    Nach einem Moment werden in der Konsole (Ihrem Terminal) zahlreiche Ausgaben im Zusammenhang mit der Ablaufverfolgung angezeigt:

    ...
    {
    Trace-ID: „9c1801593a9d3b773e5cbd314a8ea89c“,
    parentId: nicht definiert,
    traceState: nicht definiert,
    name: „fs statSync“,
    id: '2ddf082c1d609fbe',
    Art: 0,
    Zeitstempel: 1676076410782000,
    Dauer: 3,
    Attribute: {},
    Status: { Code: 0 },
    Ereignisse: [],
    Links: []
    }
    ...
    

Notiz: Lassen Sie die Terminalsitzung zur Wiederverwendung in Challenge 2 geöffnet.

Herausforderung 2: Einrichten der OTel-Instrumentierung und Trace-Visualisierung für alle Dienste

Es gibt viele Tools, mit denen Sie Spuren anzeigen und analysieren können, aber dieses Tutorial verwendet Jaeger . Jaeger ist ein einfaches, Open-Source-Framework für durchgängiges verteiltes Tracing mit einer integrierten webbasierten Benutzeroberfläche zum Anzeigen von Spans und anderen Tracing-Daten. Die im Plattform -Repository bereitgestellte Infrastruktur umfasst Jaeger (Sie haben es in Schritt 1 von Herausforderung 1 gestartet), sodass Sie sich auf die Datenanalyse konzentrieren können, anstatt sich mit komplexen Tools herumzuschlagen.

Jaeger ist über den Endpunkt http://localhost:16686 in Ihrem Browser erreichbar, wenn Sie jedoch jetzt auf den Endpunkt zugreifen, gibt es über Ihr System nichts zu sehen. Das liegt daran, dass die Spuren, die Sie gerade sammeln, an die Konsole gesendet werden! Um Ablaufverfolgungsdaten in Jaeger anzuzeigen, müssen Sie die Ablaufverfolgungen im Format des OpenTelemetry-Protokolls (OTLP) exportieren.

Bei dieser Herausforderung instrumentieren Sie den zentralen Benutzerfluss, indem Sie die Instrumentierung für Folgendes konfigurieren:

Konfigurieren Sie die automatische OTel-Instrumentierung, die an einen externen Collector gesendet wird

Zur Erinnerung: Wenn Sie die automatische OTel-Instrumentierung verwenden, müssen Sie zum Einrichten der Ablaufverfolgung nichts in der Messenger -Codebasis ändern. Stattdessen befindet sich die gesamte Ablaufverfolgungskonfiguration in einem Skript, das zur Laufzeit in den Node.js-Prozess importiert wird. Hier ändern Sie das Ziel für vom Messenger- Dienst generierte Traces von der Konsole zu einem externen Collector (in diesem Tutorial: Jaeger).

  1. Arbeiten Sie weiterhin im selben Terminal wie in Challenge 1 und installieren Sie im App- Verzeichnis des Messenger -Repos das OTLP-Exporter-Node.js-Paket:

    npm installiere @opentelemetry/exporter-trace-otlp-http@0.36.0
    

    Die Bibliothek @opentelemetry/exporter-trace-otlp-http exportiert Trace-Informationen im OTLP-Format über HTTP. Es wird beim Senden von Telemetriedaten an einen externen OTel-Sammler verwendet.

  2. Öffnen Sie tracing.mjs (das Sie in Challenge 1 erstellt und bearbeitet haben) und nehmen Sie diese Änderungen vor:

    • Fügen Sie diese Zeile zu den Importanweisungen am Anfang der Datei hinzu:

      importiere { OTLPTraceExporter } von "@opentelemetry/exporter-trace-otlp-http";
      
    • Ändern Sie den „Exporter“, den Sie dem OTel SDK bereitstellen, vom Konsolen-Exporter, der in Challenge 1 verwendet wurde, in einen, der OTLP-Daten über HTTP an einen OTLP-kompatiblen Collector senden kann. Ersetzen:

      traceExporter:neues opentelemetry.tracing.ConsoleSpanExporter(),
      

      mit:

      traceExporter: neuer OTLPTraceExporter({ headers: {} }),
      

    Notiz: Der Einfachheit halber geht das Tutorial davon aus, dass sich der Collector am Standardspeicherort http://localhost:4318/v1/traces befindet. In einem realen System ist es eine gute Idee, den Standort explizit festzulegen.

  3. Drücken Sie Strg+C , um den Nachrichtendienst zu stoppen, den Sie in diesem Terminal in Schritt 4 von „An die Konsole gesendete automatische OTel-Instrumentierung konfigurieren“ gestartet haben. Starten Sie es dann neu, um den in Schritt 2 konfigurierten neuen Exporter zu verwenden:

    ^cnode --import ./tracing.mjs index.mjs
    
  4. Starten Sie eine zweite, separate Terminalsitzung. (In den nachfolgenden Anweisungen wird dies als Client-Terminal und das ursprüngliche Terminal – das in den Schritten 1 und 3 verwendet wurde – als Messenger-Terminal bezeichnet.) Warten Sie etwa zehn Sekunden und senden Sie dann eine Integritätsprüfungsanfrage an den Nachrichtendienst (Sie können diese mehrmals ausführen, wenn Sie mehrere Spuren sehen möchten):

    curl -X GET http://localhost:4000/health
    

    Wenn Sie vor dem Senden der Anforderung zehn Sekunden warten, ist Ihr Trace leichter zu finden, da er nach den vielen Traces kommt, die die automatische Instrumentierung beim Starten des Dienstes generiert.

  5. Greifen Sie in einem Browser auf die Jaeger-Benutzeroberfläche unter http://localhost:16686 zu und überprüfen Sie, ob der OTLP-Export wie erwartet funktioniert. Klicken Sie in der Titelleiste auf Suchen und wählen Sie aus dem Dropdown-Menü im Feld Dienst den Dienst aus, dessen Name mit unknown_service beginnt. Klicken Sie auf die Schaltfläche „Spuren suchen“ :

  6. Klicken Sie auf der rechten Seite des Fensters auf eine Ablaufverfolgung, um eine Liste der darin enthaltenen Bereiche anzuzeigen. Jeder Bereich beschreibt die Vorgänge, die im Rahmen der Ablaufverfolgung ausgeführt wurden und an denen manchmal mehrere Dienste beteiligt sind. Der JsonParser- Bereich im Screenshot zeigt, wie lange es gedauert hat, den JsonParser -Teil des Anforderungsverarbeitungscodes des Messenger -Dienstes auszuführen.

    Screenshot der Jaeger-Benutzeroberfläche mit der Liste der Spans für unknown_service, bevor die automatische Instrumentierung geändert wird, um korrekte Dienstnamen anzuzeigen

  7. Wie in Schritt 5 erwähnt, ist der vom OTel SDK exportierte Name des Dienstes ( unknown_service ) nicht aussagekräftig. Um dies zu beheben, drücken Sie im Messenger-Terminal Strg+C, um den Messenger -Dienst zu stoppen. Installieren Sie dann noch ein paar Node.js-Pakete:

    ^c 
    npm installiere @opentelemetry/semantic-conventions@1.10.0 \
    @opentelemetry/resources@1.10.0
    

    Diese beiden Bibliotheken bieten die folgende Funktionalität:

    • @opentelemetry/semantic-conventions – Definiert die Standardattribute für Traces, wie in der OTel-Spezifikation definiert.
    • @opentelemetry/resources – Definiert ein Objekt (Ressource), das die Quelle darstellt, die die OTel-Daten generiert (in diesem Tutorial der Messenger- Dienst).
  8. Öffnen Sie tracing.mjs in einem Texteditor und nehmen Sie diese Änderungen vor:

    • Fügen Sie den Importanweisungen am Anfang der Datei die folgenden Zeilen hinzu:

      importiere { Ressource } von "@opentelemetry/resources"; importiere { SemanticResourceAttributes } von "@opentelemetry/semantic-conventions";
      
    • Erstellen Sie eine Ressource namens Messenger unter dem richtigen Schlüssel in der OTel-Spezifikation, indem Sie nach der letzten Importanweisung die folgende Zeile hinzufügen:

      const resource = neue Ressource({ [SemanticResourceAttributes.SERVICE_NAME]: "messenger",
      });
      
    • Übergeben Sie das Ressourcenobjekt an den NodeSDK-Konstruktor, indem Sie die orange hervorgehobene Zeile zwischen den schwarzen Zeilen hinzufügen:

      const sdk = neues opentelemetry.NodeSDK({ Ressource, traceExporter: neuer OTLPTraceExporter({ Header: {} }), Instrumentierungen: [getNodeAutoInstrumentations()], });
      
  9. Starten Sie den Messenger -Dienst neu:

    node --import ./tracing.mjs index.mjs
    
  10. Warten Sie etwa zehn Sekunden und senden Sie dann im Client-Terminal (das Sie in Schritt 4 geöffnet haben) eine weitere Integritätsprüfanforderung an den Server (Sie können den Befehl mehrmals ausführen, wenn Sie mehrere Traces sehen möchten):

    curl -X GET http://localhost:4000/health
    

    Notiz: Lassen Sie das Client-Terminal zur Wiederverwendung im nächsten Abschnitt und das Messenger-Terminal zur Wiederverwendung in Challenge 3 geöffnet.

  11. Bestätigen Sie, dass in der Jaeger-Benutzeroberfläche im Browser ein neuer Dienst namens Messenger angezeigt wird (dies kann einige Sekunden dauern und Sie müssen die Jaeger-Benutzeroberfläche möglicherweise aktualisieren):

    Screenshot der Jaeger-Benutzeroberfläche, in der Messenger in der Liste der verfügbaren Dienste für eine eingehende Prüfung von PSANS angezeigt wird

  12. Wählen Sie „Messenger“ aus dem Dropdown-Menü „Dienst“ und klicken Sie auf die Schaltfläche „Spuren suchen“ , um alle aktuellen Spuren anzuzeigen, die vom Messenger- Dienst stammen (der Screenshot zeigt die beiden aktuellsten von 20):

    Screenshot der Jaeger-Benutzeroberfläche mit den beiden aktuellsten Traces für den Messenger-Dienst

  13. Klicken Sie auf eine Spur, um die darin enthaltenen Bereiche anzuzeigen. Jeder Span wird ordnungsgemäß als vom Nachrichtendienst stammend gekennzeichnet:

    Screenshot der Jaeger-Benutzeroberfläche mit Details zu einem einzelnen Messenger-Bereich

Konfigurieren Sie die automatische OTel-Instrumentierung des Notifier-Dienstes

Starten und konfigurieren Sie nun die automatische Instrumentierung für den Benachrichtigungsdienst . Führen Sie dazu grundsätzlich dieselben Befehle aus wie in den beiden vorherigen Abschnitten für den Nachrichtendienst .

  1. Öffnen Sie eine neue Terminalsitzung (in den folgenden Schritten „Notifier-Terminal“ genannt). Wechseln Sie in das App -Verzeichnis im Notifier -Repository und installieren Sie Node.js (Sie können bei Bedarf auch eine andere Methode verwenden):

    cd ~/microservices-march/notifier/appasdf install
    
  2. Installieren Sie Abhängigkeiten:

    npm installieren
    
  3. Starten Sie die PostgreSQL-Datenbank für den Notifier -Dienst:

    Docker komponieren -d
    
  4. Erstellen Sie das Datenbankschema und die Tabellen und fügen Sie einige Seed-Daten ein:

    npm führt Refresh-DB aus
    
  5. Installieren Sie die OTel Node.js-Pakete (eine Beschreibung der Funktion der Pakete finden Sie in den Schritten 1 und 3 unter „An die Konsole gesendete OTel-Auto-Instrumentierung konfigurieren“ ):

    npm install @opentelemetry/auto-instrumentations-node@0.36.4 \
    @opentelemetry/exporter-trace-otlp-http@0.36.0 \
    @opentelemetry/resources@1.10.0 \
    @opentelemetry/sdk-node@0.36.0 \
    @opentelemetry/semantic-conventions@1.10.0
    
  6. Erstellen Sie eine neue Datei mit dem Namen tracing.mjs :

    Berührungsverfolgung.mjs
    
  7. Öffnen Sie tracing.mjs in Ihrem bevorzugten Texteditor und fügen Sie das folgende Skript hinzu, um das OTel SDK zum Laufen zu bringen:

    importiere opentelemetry von "@opentelemetry/sdk-node";
    importiere { getNodeAutoInstrumentations } von "@opentelemetry/auto-instrumentations-node";
    importiere { OTLPTraceExporter } von "@opentelemetry/exporter-trace-otlp-http";
    importiere { Resource } von "@opentelemetry/resources";
    importiere { SemanticResourceAttributes } von "@opentelemetry/semantic-conventions";
    
    const resource = new Resource({
    [SemanticResourceAttributes.SERVICE_NAME]: "notifier",
    });
    
    const sdk = new opentelemetry.NodeSDK({
    resource,
    traceExporter: new OTLPTraceExporter({ headers: {} }),
    instrumentations: [getNodeAutoInstrumentations()],
    });
    
    sdk.start();
    

    Notiz: Dieses Skript ist genau dasselbe wie das für den Messenger -Dienst, mit der Ausnahme, dass der Wert im Feld SemanticResourceAttributes.SERVICE_NAME notifier ist.

  8. Starten Sie den Benachrichtigungsdienst mit der automatischen OTel-Instrumentierung:

    node --import ./tracing.mjs index.mjs
    
  9. Warten Sie etwa zehn Sekunden und senden Sie dann im Client-Terminal eine Integritätsprüfungsanforderung an den Benachrichtigungsdienst . Dieser Dienst lauscht auf Port 5000, um Konflikte mit dem Messenger -Dienst zu vermeiden, der auf Port 4000 lauscht:

    curl http://localhost:5000/Gesundheit
    

    Notiz: Lassen Sie die Client- und Notifier-Terminals zur Wiederverwendung in Challenge 3 offen.

  10. Bestätigen Sie, dass in der Jaeger-Benutzeroberfläche im Browser ein neuer Dienst namens „Notifier“ angezeigt wird:

    Screenshot der Jaeger-Benutzeroberfläche, in der der Notifier in der Liste der verfügbaren Dienste für die eingehende Überprüfung von Spans angezeigt wird

Konfigurieren Sie die OTel-Instrumentierung von NGINX

Für NGINX richten Sie die Ablaufverfolgung manuell ein, anstatt die automatische Instrumentierungsmethode von OTel zu verwenden. Derzeit ist die gängigste Methode zum Instrumentieren von NGINX mit OTel die Verwendung eines in C geschriebenen Moduls . Module von Drittanbietern sind ein wichtiger Teil des NGINX-Ökosystems, ihre Einrichtung erfordert jedoch einige Arbeit. Dieses Tutorial übernimmt die Einrichtung für Sie. Hintergrundinformationen finden Sie unter „Kompilieren dynamischer Module von Drittanbietern für NGINX und NGINX Plus“ in unserem Blog.

  1. Starten Sie eine neue Terminalsitzung (das NGINX-Terminal ), wechseln Sie zum Stammverzeichnis des Messenger -Repository und erstellen Sie ein neues Verzeichnis namens load-balancer sowie neue Dateien namens Dockerfile , nginx.conf und opentelemetry_module.conf :

    cd ~/microservices-march/messenger/mkdir load-balancer
    cd load-balancer
    Dockerfile berühren
    nginx.conf berühren
    opentelemetry_module.conf berühren
    
  2. Öffnen Sie Dockerfile in Ihrem bevorzugten Texteditor und fügen Sie Folgendes hinzu (die Kommentare erklären, was jede Zeile macht, aber Sie können den Docker-Container erstellen und ausführen, ohne alles zu verstehen):

    FROM --platform=amd64 nginx:1.23.1 # Ersetzen Sie die Datei nginx.conf durch unsere eigene COPY nginx.conf /etc/nginx/nginx.conf # Definieren Sie die Version des NGINX OTel-Moduls ARG OPENTELEMETRY_CPP_VERSION=1.0.3 # Definieren Sie den Suchpfad für gemeinsam genutzte Bibliotheken, die beim Kompilieren und Ausführen von NGINX ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/opentelemetry-webserver-sdk/sdk_lib/lib # 1 verwendet werden. Laden Sie die neueste Version der Consul-Vorlage und des OTel C++-Webservermoduls herunter, otel-webserver-module ADD https://github.com/open-telemetry/opentelemetry-cpp-contrib/releases/download/webserver%2Fv${OPENTELEMETRY_CPP_VERSION} /opentelemetry-webserver-sdk-x64-linux.tgz /tmp RUN apt-get update \ && apt-get install -y --no-install-recommends dumb-init unzip \ # 2. Extrahieren Sie die Moduldateien && tar xvfz /tmp/opentelemetry-webserver-sdk-x64-linux.tgz -C /opt \ && rm -rf /tmp/opentelemetry-webserver-sdk-x64-linux.tgz \ # 3. Installieren und fügen Sie die Direktive „load_module“ oben in der Hauptkonfigurationsdatei von NGINX hinzu && /opt/opentelemetry-webserver-sdk/install.sh \ && echo "load_module /opt/opentelemetry-webserver-sdk/WebServerModule/Nginx/1.23.1/ngx_http_opentelemetry_module.so;\n$(cat /etc/nginx/nginx.conf)" > /etc/nginx/nginx.conf # 4. Kopieren Sie die Konfigurationsdatei für das NGINX OTel-Modul COPY opentelemetry_module.conf /etc/nginx/conf.d/opentelemetry_module.conf EXPOSE 8085 STOPSIGNAL SIGQUIT
    
  3. Öffnen Sie nginx.conf und fügen Sie Folgendes hinzu:

    Ereignisse {}
    http {
    include /etc/nginx/conf.d/opentelemetry_module.conf;
    
    Upstream Messenger {
    Server localhost:4000;
    }
    
    Server {
    listen 8085;
    
    Standort / {
    Proxy-Pass http://messenger;
    }
    }
    }
    

    Diese äußerst einfache NGINX-Konfigurationsdatei weist NGINX an:

    • Richten Sie eine Upstream-Gruppe namens Messenger ein, die die Gruppe der Messenger- Dienstinstanzen darstellt
    • Warten Sie auf HTTP-Anfragen auf Port 8085
    • Leiten Sie alle eingehenden Anfragen für Pfade, die mit / beginnen (also alle eingehenden Anfragen), an den Messenger- Upstream weiter.

    Notiz: Dies kommt der tatsächlichen Konfiguration von NGINX als Reverse-Proxy und Load Balancer in einer Produktionsumgebung ziemlich nahe. Der einzige große Unterschied besteht darin, dass das Argument der Serverdirektive im Upstream- Block normalerweise ein Domänenname oder eine IP-Adresse und nicht localhost ist.

  4. Öffnen Sie opentelemetry_module.conf und fügen Sie Folgendes hinzu:

    NginxModuleEnabled EIN;NginxModuleOtelSpanExporter otlp;
    NginxModuleOtelExporterEndpoint localhost:4317;
    NginxModuleServiceName messenger-lb;
    NginxModuleServiceNamespace MicroservicesMarchDemoArchitecture;
    NginxModuleServiceInstanceId DemoInstanceId;
    NginxModuleResolveBackends EIN;
    NginxModuleTraceAsError EIN;
    
  5. Erstellen Sie ein Docker-Image, das NGINX sowie das NGINX OTel-Modul enthält:

    Docker-Build -t Messenger-lb.
    
  6. Starten Sie den Docker-Container für den NGINX-Reverse-Proxy und Load Balancer:

    docker run --rm --name messenger-lb -p 8085:8085 --network="host" messenger-lb
    
  7. Senden Sie im Client-Terminal über den NGINX-Reverse-Proxy und den Load Balancer eine Integritätsprüfungsanfrage an den Messenger- Dienst (es besteht keine Notwendigkeit, mit dem Senden dieser Anfrage zu warten):

    curl http://localhost:8085/Gesundheit
    

    Notiz: Lassen Sie die NGINX- und Client-Terminals zur Wiederverwendung in Challenge 3 offen.

  8. Bestätigen Sie im Browser, dass der neue Messenger-lb -Dienst zusammen mit den zuvor gestarteten Diensten in der Jaeger-Benutzeroberfläche aufgeführt ist. Möglicherweise müssen Sie die Jaeger-Benutzeroberfläche in Ihrem Browser neu laden.

    Screenshot der Jaeger-Benutzeroberfläche mit einer Liste der für die eingehende Prüfung von Spans verfügbaren Dienste, jetzt einschließlich Messenger-lb

Herausforderung 3: Lernen Sie, OTel-Traces zu lesen

In „Architektur und Benutzerfluss“ haben wir die Phasen des Benutzerflusses skizziert. Hier noch einmal die Zusammenfassung:

  1. Ein Benutzer beginnt eine Konversation, indem er einem anderen Benutzer eine Nachricht sendet.
  2. Der NGINX-Reverse-Proxy fängt die Nachricht ab und leitet sie an den Messenger -Dienst weiter.
  3. Der Messenger- Dienst schreibt die Nachricht in seine Datenbank und versendet dann ein Ereignis über RabbitMQ.
  4. Der Benachrichtigungsdienst verarbeitet dieses Ereignis, sucht nach den Benachrichtigungseinstellungen des Empfängers (zweiten Benutzers) und sendet dem Empfänger über die bevorzugte Methode eine Benachrichtigung.

Und die Ziele der Implementierung der Telemetrie sind:

  1. Verstehen Sie alle Schritte, die eine Anfrage durchläuft, um den neuen Nachrichtenfluss zu erreichen.
  2. Sie können darauf vertrauen, dass der Flow unter normalen Bedingungen innerhalb von fünf Sekunden durchgehend ausgeführt wird.
  3. Sehen Sie, wie lange der Benachrichtigungsdienst braucht, um mit der Verarbeitung des vom Nachrichtendienst versendeten Ereignisses zu beginnen.

In dieser Herausforderung lernen Sie, wie Sie bewerten, ob die von der OTel-Instrumentierung generierten Spuren die oben genannten Ziele erfüllen. Zuerst testen Sie das System und erstellen einige Spuren . Anschließend untersuchen Sie die Ablaufverfolgung auf einen Nachrichtenfluss und die Abschnitte davon, die von NGINX , dem Messenger- Dienst und dem Benachrichtigungsdienst generiert wurden.

Erstellen von Trace-Daten

Richten Sie im Client-Terminal eine Konversation ein und senden Sie ein paar Nachrichten zwischen zwei Benutzern:

curl -X POST \
-H "Inhaltstyp: application/json" \
-d '{"participant_ids": [1, 2]}' \
'http://localhost:8085/conversations'

curl -X POST \
-H "Benutzer-ID: 1" \
-H "Inhaltstyp: application/json" \
-d '{"Inhalt": "Dies ist die erste Nachricht"}' \
'http://localhost:8085/conversations/1/messages'

curl -X POST \
-H "Benutzer-ID: 2" \
-H "Inhaltstyp: application/json" \
-d '{"Inhalt": "Dies ist die zweite Nachricht"}' \
'http://localhost:8085/conversations/1/messages'

Eine Ausgabe ähnlich der folgenden wird vom Notifier -Dienst generiert und im Notifier-Terminal angezeigt:

Neue Nachricht empfangen: {"type":"new_message","channel_id":1,"user_id":1,"index":1,"participant_ids":[1,2]}Benachrichtigung über neue Nachricht wird per SMS an 12027621401 gesendet

Neue Nachricht empfangen: {"type":"new_message","channel_id":1,"user_id":2,"index":2,"participant_ids":[1,2]}

Benachrichtigung über neue Nachricht wird per E-Mail an the_hotstepper@kamo.ze gesendet

Benachrichtigung über neue Nachricht wird per SMS an 19147379938 gesendet

Machen Sie sich bereit, die Spuren zu lesen

Öffnen Sie die Jaeger-Benutzeroberfläche im Browser, wählen Sie „messenger-lb“ aus dem Dropdown-Menü „Dienst“ und klicken Sie auf die Schaltfläche „Traces suchen“ . Es wird eine Liste mit Spuren angezeigt, beginnend am Anfang des Flusses. Klicken Sie auf eine beliebige Ablaufverfolgung, um Details dazu anzuzeigen, wie in diesem Screenshot:

Screenshot der Jaeger-Benutzeroberfläche, die den gesamten Satz von Spans im Flow zeigt

Klicken Sie herum und erkunden Sie ein wenig. Überlegen Sie dann, bevor Sie fortfahren, wie die Informationen in den Spuren Ihre Instrumentierungsziele unterstützen, wie in der Einleitung zu Herausforderung 3 aufgeführt. Zu den relevanten Fragen gehören:

  • Welche Informationen helfen, die Ziele zu erreichen?
  • Welche Informationen fehlen?
  • Welche Informationen sind nicht relevant?

Untersuchen Sie den NGINX-Abschnitt (messenger-lb) des Trace

Ziel 1: Alle Schritte anzeigen, die eine Anfrage im neuen Nachrichtenfluss durchläuft

Beginnen Sie mit dem NGINX-Span, der innerhalb des übergeordneten Spans 11 untergeordnete Spans hat. Da die aktuelle NGINX-Konfiguration sehr einfach ist, sind die untergeordneten Bereiche nicht sehr interessant und zeigen lediglich die für jeden Schritt im Lebenszyklus der NGINX-Anforderungsverarbeitung benötigte Zeit. Der übergeordnete Bereich (der allererste) enthält jedoch einige interessante Erkenntnisse:

Screenshot der Jaeger-Benutzeroberfläche, der den übergeordneten Span im NGINX-Abschnitt (messenger-lb) der Ablaufverfolgung zeigt

  • Unter Tags sehen Sie die folgenden Attribute:

    • http.method- Feld – POST (in REST- Begriffen bedeutet dies Erstellung)
    • http.status_code -Feld –201 (zeigt erfolgreiche Erstellung an)
    • http.target- Feld – conversations/1/messages (der Nachrichtenendpunkt)

    Zusammengefasst ergeben diese drei Informationen: „Eine POST- Anfrage wurde an /conversations/1/messages gesendet und die Antwort war201 (erfolgreich erstellt)“. Dies entspricht den Schritten 1 und 4a in „Architektur und Benutzerfluss“ ).

  • Unter „Prozess“ zeigt das Feld „webengine.name“ , dass dies der NGINX-Teil der Anfrage ist.

Darüber hinaus können Sie erkennen, dass die über den NGINX-Reverse-Proxy an den Messenger- Dienst gesendete Anfrage alle erwarteten Komponenten im Flow getroffen hat, weil die Spans für Messenger -lbconversations/1“ verschachtelt sind (siehe Screenshot in „Machen Sie sich bereit zum Lesen der Traces “).

Diese Information erfüllt das Ziel, da Sie sehen können, dass der NGINX-Reverse-Proxy Teil des Flusses war.

Ziel 2: Überprüfen Sie, ob der Flow innerhalb von fünf Sekunden ausgeführt wird

Sehen Sie sich in der Liste der Spans mit der Bezeichnung „messenger-lb“ den aktuellsten Span an (er steht ganz unten in der Liste), um zu sehen, wie lange der NGINX-Teil der Anfrage gedauert hat. Im Screenshot begann der Bereich bei 589 Mikrosekunden (µs) und dauerte 24µs, was bedeutet, dass der komplette Reverse-Proxy-Vorgang nur 613 µs dauerte – etwa 0,6 Millisekunden (ms). (Die genauen Werte sind natürlich anders, wenn Sie das Tutorial selbst ausführen.)

Screenshot der Jaeger-Benutzeroberfläche mit Spans im NGINX-Abschnitt (messenger-lb) des Trace

In einem solchen Aufbau sind die Werte größtenteils nur im Verhältnis zu anderen Messungen nützlich und variieren zwischen Systemen. In diesem Fall besteht jedoch eindeutig keine Gefahr, dass dieser Vorgang annähernd fünf Sekunden dauert.

Diese Information erfüllt das Ziel, da Sie sehen können, dass die NGINX-Operationen nicht annähernd fünf Sekunden gedauert haben. Wenn es im Ablauf einen sehr langsamen Vorgang gibt, muss dieser später erfolgen.

Ziel 3: Sehen Sie, wie lange der Benachrichtigungsdienst braucht, um das vom Nachrichtendienst gesendete Ereignis zu lesen

Die Reverse-Proxy-Schicht von NGINX enthält hierzu keine Informationen, Sie können also mit den Messenger- Spans fortfahren.

Untersuchen Sie den Messenger-Abschnitt des Trace

Ziel 1: Alle Schritte anzeigen, die eine Anfrage im neuen Nachrichtenfluss durchläuft

Der Messengerdienst -Abschnitt des Trace enthält weitere 11 Spans. Auch hier betreffen die meisten untergeordneten Bereiche die grundlegenden Schritte, die das Express-Framework bei der Verarbeitung einer Anforderung verwendet, und sind nicht sehr interessant. Der übergeordnete Span (der allererste) enthält jedoch wiederum einige interessante Erkenntnisse:

Screenshot der Jaeger-Benutzeroberfläche, die den übergeordneten Span im Messenger-Abschnitt der Ablaufverfolgung zeigt

Unter Tags sehen Sie die folgenden Attribute:

  • http.method- Feld – POST (in REST-Begriffen bedeutet dies wiederum „Erstellung“)
  • http.route- Feld – /conversations/:conversationId/messages (die Nachrichtenroute)
  • http.target- Feld – /conversations/1/messages (der Nachrichtenendpunkt)

Diese Information erfüllt das Ziel, da sie uns zeigt, dass der Messenger- Dienst Teil des Flusses war und der getroffene Endpunkt der neue Nachrichtenendpunkt war.

Ziel 2: Überprüfen Sie, ob der Flow innerhalb von fünf Sekunden ausgeführt wird

Wie im folgenden Screenshot gezeigt, begann der Messenger -Teil der Ablaufverfolgung bei 1,28 ms und endete bei 36,28 ms, was eine Gesamtzeit von 35 ms ergibt. Die meiste Zeit wurde mit dem Parsen von JSON ( Middleware jsonParser ) und in noch größerem Umfang mit der Verbindung zur Datenbank ( pg-pool.connect und tcp.connect ) verbracht.

Dies ist vor dem Hintergrund sinnvoll, dass beim Verfassen der Nachricht auch mehrere SQL-Abfragen erfolgen. Dies wiederum legt nahe, dass Sie möglicherweise die Konfiguration der automatischen Instrumentierung erweitern möchten, um den Zeitpunkt dieser Abfragen zu erfassen. (Das Tutorial zeigt diese zusätzliche Instrumentierung nicht, aber in Challenge 4 erstellen Sie manuell Spans, die wiederum zum Umschließen von Datenbankabfragen verwendet werden können.)

Screenshot der Jaeger-Benutzeroberfläche, der die Spannen im Messenger-Abschnitt des Trace und deren Dauer zeigt

Mit dieser Information ist das Ziel erreicht, denn sie zeigt, dass die Vorgänge des Messengers nicht einmal annähernd fünf Sekunden dauern. Wenn es im Ablauf einen sehr langsamen Vorgang gibt, muss dieser später erfolgen.

Ziel 3: Sehen Sie, wie lange der Benachrichtigungsdienst braucht, um das vom Nachrichtendienst gesendete Ereignis zu lesen

Da die Messenger- Spans diese Informationen ebenso wenig enthalten wie die NGINX-Spans, können Sie zu den Notifier -Spans wechseln.

Untersuchen Sie den Abschnitt „Notifier“ des Trace

Ziel 1: Alle Schritte anzeigen, die eine Anfrage im neuen Nachrichtenfluss durchläuft

Der Benachrichtigungsabschnitt der Ablaufverfolgung enthält nur zwei Bereiche:

Screenshot der Jaeger-Benutzeroberfläche, der die beiden Bereiche im Benachrichtigungsbereich der Ablaufverfolgung zeigt

  • Der Prozessbereich „chat_queue“ – Bestätigt, dass der Notifier -Dienst ein Ereignis aus der Nachrichtenwarteschlange „chat_queue“ verarbeitet hat.
  • Der pg-pool.connect- Bereich – Zeigt, dass der Notifier- Dienst nach der Verarbeitung des Ereignisses eine Verbindung zu seiner Datenbank hergestellt hat.

Die aus diesen Spannen verfügbaren Informationen erfüllen das Ziel, jeden Schritt zu verstehen, nur teilweise. Sie können sehen, dass der Benachrichtigungsdienst den Punkt erreicht hat, an dem er das Ereignis aus der Warteschlange verarbeitet, aber Sie wissen nicht, ob:

  • Die von diesem Dienst gesendete Nachrichtenbenachrichtigung entspricht dem vom Nachrichtendienst gesendeten Ereignis
  • Die entsprechenden Nachrichtenbenachrichtigungen wurden korrekt an den Empfänger der Nachricht gesendet

Dies bedeutet, dass Sie Folgendes tun müssen, um den Ablauf des Notifier- Dienstes vollständig zu verstehen:

  • Manuelles Instrumentieren der Bereiche, die den Versand einer Benachrichtigung anzeigen
  • Stellen Sie sicher, dass eine explizite Verbindung zwischen dem vom Nachrichtendienst gesendeten Ereignis und dem vom Benachrichtigungsdienst verwendeten Ereignis in Form einer Trace-ID besteht.

Ziel 2: Überprüfen Sie, ob der Flow innerhalb von fünf Sekunden ausgeführt wird

Wenn Sie die Gesamtdauer der Benachrichtigungsdienstspannen betrachten, sehen Sie, dass die Anforderung 30,77 ms im Benachrichtigungsabschnitt des Flusses verbracht hat. Da es jedoch keine Zeitspannen gibt, die das „Ende“ des gesamten Flusses (das Senden von Benachrichtigungen an den Empfänger) signalisieren, können Sie weder die Gesamtdauer dieses Abschnitts des Flusses noch die Gesamtabschlusszeit für den Vorgang bestimmen.

Ziel 3: Sehen Sie, wie lange der Benachrichtigungsdienst braucht, um das vom Nachrichtendienst gesendete Ereignis zu lesen

Sie können jedoch sehen, dass ein Chat-Queue -Prozessbereich für den Benachrichtigungsdienst bei 6,12 ms begann, 2 ms nachdem ein Chat- Queue -Sendebereich für den Messenger- Dienst bei 4,12 ms begann.

Screenshot der Jaeger-Benutzeroberfläche, der den Benachrichtigungsdienst zeigt, der ein vom Nachrichtendienst gesendetes Ereignis verarbeitet.

Dieses Ziel wird erreicht, weil Sie wissen, dass der Notifier ein Ereignis 2 ms nach der Versendung durch den Nachrichtendienst verbraucht hat. Im Gegensatz zu Ziel 2 ist es zum Erreichen dieses Ziels nicht erforderlich, dass Sie wissen, ob das Ereignis vollständig verarbeitet wurde oder wie lange dies gedauert hat.

Schlussfolgerungen

Basierend auf unserer Analyse der von der aktuellen automatischen OTel-Instrumentierung erzeugten Spuren ist Folgendes klar:

  • Viele dieser Spannen sind in ihrer aktuellen Form nicht nützlich:

    • NGINX erzeugt Spans im Zusammenhang mit Funktionen – wie etwa Autorisierungsprüfung und Dateibereitstellung – die für die für Sie wichtige Rolle, das Reverse-Proxying, nicht relevant sind. Allerdings erlaubt die OTel-Instrumentierung für NGINX an diesem Punkt nicht, irrelevante Bereiche wegzulassen, sodass nichts getan werden kann.
    • Unter den Spans für die Node.js-Dienste (die Messenger- und Notifier- Dienste) scheinen einige für die Ziele relevant zu sein: die Spans für die JSON-Analyse, den Anforderungshandler und alle Datenbankvorgänge. Einige der Middleware-Spans (wie expressInit und corsMiddleware ) scheinen nicht relevant und können entfernt werden.
  • Für Folgendes fehlen kritische Spannen:

    • Vom Notifier- Dienst gesendete Benachrichtigungen
    • Eine klare Zuordnung zwischen dem vom Messenger -Dienst gesendeten RabbitMQ-Ereignis und dem vom Benachrichtigungsdienst verarbeiteten Ereignis

Das heißt, die Grundinstrumentierung erfüllt das letzte Ziel:

  • Sehen Sie, wie lange der Benachrichtigungsdienst braucht, um mit der Verarbeitung des vom Nachrichtendienst gesendeten Ereignisses zu beginnen

Allerdings liegen nicht genügend Informationen vor, um die ersten beiden Ziele zu erreichen:

  • Verstehen Sie alle Schritte, die eine Anfrage während des neuen Nachrichtenflusses durchläuft
  • Sie können sicher sein, dass der Flow unter normalen Umständen in weniger als fünf Sekunden von Ende zu Ende ausgeführt wird.

Herausforderung 4: Optimieren Sie Ihre Instrumente anhand von Trace-Messwerten

In dieser Herausforderung optimieren Sie die OTel-Instrumentierung basierend auf den Trace-Analysen, die Sie in Herausforderung 3 durchgeführt haben. Hierzu gehört sowohl das Entfernen unnötiger Spans , das Erstellen neuer benutzerdefinierter Spans als auch die Bestätigung , dass das vom Benachrichtigungsdienst verwendete Ereignis das vom Nachrichtendienst generierte Ereignis ist.

Entfernen Sie unnötige Spannen

  1. Öffnen Sie in Ihrem bevorzugten Texteditor die Datei tracing.mjs im App- Verzeichnis des Messenger -Repositorys und fügen Sie am Ende der Liste der Importanweisungen oben Folgendes hinzu:

    const IGNORED_EXPRESS_SPANS = neues Set([ "Middleware - expressInit",
    "Middleware - corsMiddleware",
    ]);
    

    Dadurch wird eine Reihe von Span-Namen definiert, die aus der Liste der Spans abgeleitet werden, die im folgenden Screenshot der Jaeger-Benutzeroberfläche angezeigt wird und aus der Ablaufverfolgung weggelassen werden sollen, da sie keine nützlichen Informationen für diesen Fluss liefern. Möglicherweise entscheiden Sie, dass andere im Screenshot aufgeführte Bereiche ebenfalls nicht benötigt werden, und fügen sie der Liste IGNORED_EXPRESS_SPANS hinzu.

    Screenshot der Jaeger-Benutzeroberfläche mit einer Liste mehrerer Spans des Messenger-Dienstes, die möglicherweise relevante Informationen liefern und daher aus der Ablaufverfolgung weggelassen werden können.

  2. Fügen Sie der Autoinstrumentierungskonfiguration Filter hinzu, um unerwünschte Bereiche auszulassen, indem Sie die orange hervorgehobene Zeile ändern:

    const sdk = neues opentelemetry.NodeSDK({ Ressource, traceExporter: neuer OTLPTraceExporter({ Header: {} }), Instrumentierungen: [getNodeAutoInstrumentations()], });
    

    dazu:

    const sdk = neues opentelemetry.NodeSDK({ Ressource, traceExporter: neuer OTLPTraceExporter({ Header: {} }), Instrumentierungen: [ getNodeAutoInstrumentations({ "@opentelemetry/instrumentation-express": { ignoreLayers: [ (Name) => { return IGNORED_EXPRESS_SPANS.has(Name); }, ], }, }), ], });
    

    Die Funktion getNodeAutoInstrumentations verweist auf die in Schritt 1 definierte Gruppe von Spans, um sie aus der von @opentelemetry/instrumentation-express generierten Ablaufverfolgung herauszufiltern. Mit anderen Worten: Für einen Span, der zu IGNORED_EXPRESS_SPANS gehört, ergibt die Anweisung „return“true“ , und die Anweisung „ignoreLayers“ entfernt diesen Span aus der Ablaufverfolgung.

  3. Drücken Sie im Messenger-Terminal Strg+C , um den Messenger -Dienst zu stoppen. Starten Sie es dann neu:

    ^cnode --import ./tracing.mjs index.mjs
    
  4. Warten Sie etwa zehn Sekunden und senden Sie dann im Client-Terminal eine neue Nachricht:

    curl -X POST \ -H "Benutzer-ID: 2" \
    -H "Inhaltstyp: application/json" \
    -d '{"Inhalt": "Dies ist die zweite Nachricht"}' \
    'http://localhost:8085/conversations/1/messages'
    
  5. Überprüfen Sie die Messenger- Spans in der Jaeger-Benutzeroberfläche erneut. Die beiden Middleware -Spans expressInit und corsMiddleware werden nicht mehr angezeigt (Sie können dies mit dem Screenshot für Ziel 2 von „ Untersuchen Sie den Messenger-Abschnitt der Ablaufverfolgung in Herausforderung 3“ vergleichen).

    Screenshot der Jaeger-Benutzeroberfläche, der zeigt, dass die Ablaufverfolgung keine zwei Bereiche mehr enthält, nachdem Sie die Instrumentierung geändert haben, um sie aus der Ablaufverfolgung herauszufiltern

Einrichten von benutzerdefinierten Spannen

In diesem Abschnitt berühren Sie zum ersten Mal den Anwendungscode. Durch die automatische Instrumentierung werden zahlreiche Informationen generiert, ohne dass Änderungen an der Anwendung erforderlich sind. Einige Erkenntnisse sind jedoch nur durch die Instrumentierung bestimmter Teile der Geschäftslogik möglich.

Ein Beispiel für den neuen Nachrichtenfluss, den Sie instrumentieren, ist die Verfolgung des Sendens von Benachrichtigungen an den Empfänger der Nachricht.

  1. Öffnen Sie index.mjs im App- Verzeichnis des Notifier- Repository. Diese Datei enthält die gesamte Geschäftslogik für den Dienst. Fügen Sie am Ende der Liste der Importanweisungen oben in der Datei die folgende Zeile hinzu:

    importiere { trace } von "@opentelemetry/api";
    
  2. Ersetzen Sie diesen Code (ungefähr in Zeile 91 der Datei):

    for (let pref of preferences) { console.log( `Benachrichtigung über neue Nachricht senden über${pref.address_type} Zu${pref.address} ` ); }
    

    mit:

    const tracer = trace.getTracer("notifier"); // 1tracer.startActiveSpan( // 2 "notification.send_all", { Attribute: { user_id: msg.user_id, }, }, (parentSpan) => { für (let pref of preferences) { tracer.startActiveSpan( // 3 "notification.send", { Attribute: { // 4 notification_type: pref.address_type, user_id: pref.user_id, }, }, (span) => { console.log( `Benachrichtigung über neue Nachricht senden über${pref.address_type} Zu${pref.address} `); span.end(); // 5 } ); } parentSpan.end(); // 6 } );
    

    Der neue Code bewirkt Folgendes:

    1. Ruft den Tracer ab, ein globales Objekt für die Interaktion mit OTel-Traces.
    2. Startet einen neuen übergeordneten Span namens „notification.send_all“ und legt das Attribut „user_id“ fest, um den Absender der Nachricht zu identifizieren.
    3. Führt eine Schleife aus, in der die Benachrichtigungseinstellungen des Empfängers aufgelistet werden und ein neuer untergeordneter Span mit dem Namen notification.send unter notification.send_all erstellt wird. Jede Benachrichtigung generiert einen neuen Span.
    4. Legt weitere Attribute für den untergeordneten Bereich fest:

      • notification_typeSMS oder E-Mail
      • user_id – Die ID des Benutzers, der die Benachrichtigung erhält
    5. Schließt nacheinander alle untergeordneten Benachrichtigungen . Sendebereich.
    6. Schließt den übergeordneten Bereich „notification.send_all“ .

    Durch einen übergeordneten Bereich wird garantiert, dass jeder Vorgang zum Senden einer Benachrichtigung gemeldet wird, auch wenn keine Benachrichtigungseinstellungen für den Benutzer erkannt werden.

  3. Drücken Sie im Notifier-Terminal Strg+C , um den Notifier -Dienst zu stoppen. Starten Sie es dann neu:

    ^cnode --import ./tracing.mjs index.mjs
    
  4. Warten Sie etwa zehn Sekunden und senden Sie dann im Client-Terminal eine neue Nachricht:

    curl -X POST \ -H "Benutzer-ID: 2" \
    -H "Inhaltstyp: application/json" \
    -d '{"Inhalt": "Dies ist die zweite Nachricht"}' \
    'http://localhost:8085/conversations/1/messages'
    
  5. Überprüfen Sie die Benachrichtigungsbereiche in der Jaeger-Benutzeroberfläche erneut. Sie sehen den übergeordneten Bereich und zwei untergeordnete Bereiche, jeweils mit der Operation „Benachrichtigung senden“:

    Screenshot der Jaeger-GUI, der das Ergebnis der Definition von drei neuen Spans im Code für den Benachrichtigungsdienst zeigt

Sie können jetzt das erste und zweite Ziel vollständig erreichen, da Sie alle Schritte sehen können, die eine Anforderung während des neuen Nachrichtenflusses durchläuft. Die Zeitangaben in jedem Abschnitt zeigen etwaige Verzögerungen zwischen diesen Schritten an.

Bestätigen Sie, dass Messenger und Notifier dasselbe Ereignis verarbeiten

Für den vollständigen Einblick in den Ablauf benötigen Sie noch eine weitere Sache. Ist das vom Benachrichtigungsdienst verarbeitete Ereignis tatsächlich das vom Nachrichtendienst versendete?

Sie müssen keine expliziten Änderungen vornehmen, um die beiden Spuren zu verbinden – Sie möchten aber auch nicht blind der Magie der automatischen Instrumentierung vertrauen.

Fügen Sie in diesem Sinne schnell einen Debug-Code hinzu, um zu überprüfen, ob der im NGINX-Dienst gestartete Trace tatsächlich derselbe ist (dieselbe Trace-ID hat) wie der vom Benachrichtigungsdienst verwendete.

  1. Öffnen Sie die Datei index.mjs im App- Verzeichnis des Messenger -Repositorys und nehmen Sie diese Änderungen vor:

    • Fügen Sie am Ende der Liste mit den Importanweisungen oben die folgende Zeile hinzu:

      importiere { trace } von "@opentelemetry/api";
      
    • Fügen Sie die orange hervorgehobenen Zeilen unterhalb der vorhandenen schwarzen Zeile hinzu:

      asynchrone Funktion createMessageInConversation(req, res) { const tracer = trace.getActiveSpan(); console.log("TRACE_ID: ", tracer.spanContext().traceId);
      

      Die neuen Zeilen drucken die TRACE_ID aus der Funktion im Messenger aus, die die Erstellung einer neuen Nachricht handhabt.

  2. Öffnen Sie die Datei index.mjs im App- Verzeichnis des Notifier- Repositorys und fügen Sie die orange hervorgehobene Zeile unterhalb der vorhandenen schwarzen Zeile hinzu:

    Exportiere die asynchrone Funktion handleMessageConsume (Kanal, Nachricht, Handler) { console.log("RABBIT_MQ_MESSAGE: ", Nachricht);
    

    Die neue Zeile druckt den vollständigen Inhalt des vom Benachrichtigungsdienst empfangenen AMQP-Ereignisses.

  3. Stoppen und starten Sie die Messenger- und Notifier- Dienste neu, indem Sie diese Befehle sowohl im Messenger- als auch im Notifier-Terminal ausführen:

    ^cnode --import ./tracing.mjs index.mjs
    
  4. Warten Sie etwa zehn Sekunden und senden Sie dann im Client-Terminal erneut eine Nachricht:

    curl -X POST \ -H "Benutzer-ID: 2" \
    -H "Inhaltstyp: application/json" \
    -d '{"Inhalt": "Dies ist die zweite Nachricht"}' \
    'http://localhost:8085/conversations/1/messages'
    
  5. Sehen Sie sich die Protokolle der Messenger- und Benachrichtigungsdienste an. Das Protokoll des Messenger -Dienstes enthält eine Zeile wie diese, die die Trace-ID für eine Nachricht angibt (die tatsächliche ID wird anders sein, wenn Sie das Lernprogramm ausführen):

    TRACE_ID:  29377a9b546c50be629c8e64409bbfb5
    
  6. In ähnlicher Weise meldet das Notifier- Dienstprotokoll eine Trace-ID in einer Ausgabe wie dieser:

    _spanContext: {
    Trace-ID: '29377a9b546c50be629c8e64409bbfb5', spanId: 'a94e9462a39e6dbf', TraceFlags: 1,
    traceState: nicht definiert
    },
    
  7. Die Trace-IDs stimmen in der Konsole überein, aber als letzten Schritt können Sie sie mit der Trace-ID in der Jaeger-Benutzeroberfläche vergleichen. Öffnen Sie die Benutzeroberfläche am entsprechenden Endpunkt der Trace-ID (Ihr Endpunkt ist anders, in diesem Beispiel ist es jedoch http://localhost:16686/trace/29377a9b546c50be629c8e64409bbfb5 ), um den gesamten Trace anzuzeigen. Die Jaeger-Spur bestätigt Folgendes:

    • Die automatische AMQP-Instrumentierung im Messenger- Dienst fügt diese Trace-ID als Teil der Metadaten hinzu, wenn das Ereignis versendet wird.
    • Die AMQP-Autoinstrumentierung im Benachrichtigungsdienst erwartet diese Metadaten und legt den Ablaufverfolgungskontext entsprechend fest.

Notiz: In einem echten Produktionssystem würden Sie den Code, den Sie in diesem Abschnitt hinzugefügt haben, entfernen, sobald Sie bestätigt haben, dass der Ablauf wie erwartet funktioniert.

Ressourcenbereinigung

Sie haben im Laufe dieses Tutorials einige Container und Bilder erstellt! Befolgen Sie diese Anweisungen, um sie zu entfernen.

  • So entfernen Sie alle laufenden Docker-Container:

    docker rm $(docker stop messenger-lb)
    
  • So entfernen Sie den Plattformdienst und die Messenger- und Notifier- Datenbankdienste:

    cd ~/microservices-march/platform && docker compose down
    cd ~/microservices-march/notifier && docker compose down
    cd ~/microservices-march/messenger && docker compose down
    

Nächste Schritte

Herzlichen Glückwunsch, Sie haben das Tutorial abgeschlossen!

  • Sie richten die OTel-Instrumentierung über einen NGINX-Reverse-Proxy und zwei Node.js-Dienste ein.
  • Sie haben die von der automatischen Instrumentierung von OTel bereitgestellten Daten kritisch betrachtet und einige Telemetriedaten hinzugefügt, die zum Erreichen der OTel-Laborziele fehlten:
    • Sie haben eine angemessene Ansicht des Flusses einer bestimmten Anforderung durch ein Nachrichtensystem erhalten, ohne den Anwendungscode direkt zu ändern.
    • Sie haben bestätigt, dass der Flow unter normalen Umständen in weniger als fünf Sekunden von Ende zu Ende ausgeführt wurde.

Und dennoch haben Sie gerade erst an der Oberfläche dessen gekratzt, wie eine ideale Tracing-Konfiguration aussehen könnte! In einer Produktionsumgebung möchten Sie möglicherweise Dinge wie benutzerdefinierte Spans für jede Datenbankabfrage und zusätzliche Metadaten zu allen Spans hinzufügen, die Laufzeitdetails wie die Container-ID jedes Dienstes beschreiben. Sie können auch die beiden anderen Arten von OTel-Daten (Metriken und Protokollierung) implementieren, um ein vollständiges Bild des Zustands Ihres Systems zu erhalten.

Um Ihre Microservices-Ausbildung fortzusetzen, sehen Sie sich Microservices März 2023 an. In Einheit 4: Bewältigen Sie Chaos und Komplexität bei Microservices mit Observability . Sie erfahren mehr über die drei Hauptklassen von Observability-Daten, die Bedeutung der Ausrichtung von Infrastruktur und App und Möglichkeiten, mit der Analyse von Deep Data zu beginnen.


„Dieser Blogbeitrag kann auf Produkte verweisen, die nicht mehr verfügbar und/oder nicht mehr unterstützt werden. Die aktuellsten Informationen zu verfügbaren F5 NGINX-Produkten und -Lösungen finden Sie in unserer NGINX-Produktfamilie . NGINX ist jetzt Teil von F5. Alle vorherigen NGINX.com-Links werden auf ähnliche NGINX-Inhalte auf F5.com umgeleitet."