Tracing und Monitoring in Istio: Mikrodienste und das Prinzip der Unbestimmtheit

Das Heisenbergsche UnschÀrfeprinzip besagt, dass man nicht gleichzeitig die Position eines Objekts und dessen Geschwindigkeit messen kann. Befindet sich das Objekt in Bewegung, hat es keinen festen Ort. Und wenn es eine Position hat, dann hat es keine Geschwindigkeit.

Tracing und Monitoring in Istio: Mikrodienste und das Prinzip der Unbestimmtheit

Was die Mikrodienste auf der Red Hat OpenShift-Plattform (verwalten durch Kubernetes) betrifft, so können sie dank entsprechender Open-Source-Software gleichzeitig ĂŒber ihre Leistung sowie ihre VerfĂŒgbarkeit berichten. Das widerlegt zwar nicht den alten Heisenberg, beseitigt jedoch die Ungewissheit bei der Arbeit mit Cloud-Anwendungen. Istio ermöglicht eine einfache Organisation von Tracing und Monitoring solcher Anwendungen, um alles unter Kontrolle zu halten.

Terminologie festlegen

Pod Tracing (Tracing) verstehen wir als die Protokollierung von SystemaktivitĂ€ten. Es klingt zwar recht allgemein, aber eine der wichtigsten Regeln hier lautet, dass die Trace-Daten in das entsprechende Speichersystem zurĂŒckgespielt werden, ohne sich um deren Formatierung zu sorgen. Die gesamte Arbeit mit der Suche und Analyse der Daten obliegt dem Verbraucher. In Istio wird das Tracing-System Jaeger verwendet, das das OpenTracing-Datenmodell umsetzt.

Traces (Traces, und das Wort „Traces“ wird hier im Sinne von „Spuren“, wie zum Beispiel bei der ballistischen Expertise, verwendet) nennen wir die Daten, die den Verlauf einer Anfrage oder einer Arbeitseinheit vollstĂ€ndig beschreiben, sozusagen „von Anfang bis Ende“. Zum Beispiel alles, was passiert, sobald der Benutzer auf den Button auf der Webseite klickt, bis zu dem Moment, in dem die Daten zurĂŒckgegeben werden, einschließlich aller dabei beteiligten Mikrodienste. Man kann sagen, dass ein Trace den Verlauf der Anfrage in beide Richtungen vollstĂ€ndig beschreibt (oder modelliert). Im Jaeger-Interface werden die Traces zeitlich aufgeschlĂŒsselt, Ă€hnlich wie eine Kette in einzelne Glieder zerlegt werden kann. Anstelle von Gliedern besteht ein Trace aus sogenannten Spans.

Span – ist das Intervall vom Beginn der AusfĂŒhrung einer Arbeitseinheit bis zu ihrem Abschluss. Wenn wir das Bild weiterfĂŒhren, kann man sagen, dass jeder Span ein einzelnes Glied der Kette darstellt. Ein Span kann ein oder mehrere untergeordnete Spans haben (oder auch nicht). Folglich hat der Root Span die gleiche Gesamtdauer wie der Trace, zu dem er gehört.

Überwachung Das ist im Wesentlichen die Beobachtung Ihres Systems – mit den Augen, ĂŒber die BenutzeroberflĂ€che oder durch Automatisierungswerkzeuge. Der Überwachung liegen Nachverfolgungsdaten zugrunde. In Istio wird das Monitoring mit Hilfe von Prometheus umgesetzt und verfĂŒgt ĂŒber eine entsprechende BenutzeroberflĂ€che. Prometheus unterstĂŒtzt die automatische Überwachung mithilfe von Alerts und Alert Managers.

Wir machen Striche

Um die Nachverfolgung zu ermöglichen, muss die Anwendung eine Sammlung von Spans erstellen. Diese mĂŒssen dann nach Jaeger exportiert werden, damit dieser ein visuelles Darstellung der Nachverfolgung erstellen kann. Unter anderem kennzeichnen diese Spans den Namen der Operation sowie die Zeitstempel ihres Beginns und Endes. Die Übertragung der Spans erfolgt durch das Weiterleiten der fĂŒr Jaeger vorgesehenen HTTP-Header von eingehenden zu ausgehenden Anfragen. Je nach Programmiersprache kann es erforderlich sein, den Quellcode der Anwendungen geringfĂŒgig zu modifizieren. Im Folgenden ist ein Beispiel fĂŒr Java (bei Verwendung des Frameworks Spring Boot) zu sehen, das die B3-Header (im Zipkin-Stil) zu Ihrer Anfrage im Konfigurationsklasse von Spring hinzufĂŒgt:

Tracing und Monitoring in Istio: Mikrodienste und das Prinzip der Unbestimmtheit
Dabei werden die folgenden Header-Einstellungen verwendet:

Tracing und Monitoring in Istio: Mikrodienste und das Prinzip der Unbestimmtheit
Wenn Sie Java verwenden, können Sie den Code unverĂ€ndert lassen und einfach ein paar Zeilen in die Maven POM-Datei hinzufĂŒgen und Umgebungsvariablen festlegen. Folgende Zeilen mĂŒssen zur POM.XML-Datei hinzugefĂŒgt werden, um den Jaeger Tracer Resolver zu integrieren:

Tracing und Monitoring in Istio: Mikrodienste und das Prinzip der Unbestimmtheit
Die entsprechenden Umgebungsvariablen werden im Dockerfile festgelegt:

Tracing und Monitoring in Istio: Mikrodienste und das Prinzip der Unbestimmtheit
Alles ist nun eingestellt, und unsere Mikrodienste werden anfangen, Nachverfolgungsdaten zu generieren.

Ein allgemeiner Überblick

Istio enthÀlt ein einfaches Dashboard, das auf Grafana basiert. Wenn alles konfiguriert ist und auf der Red Hat OpenShift PaaS-Plattform (in unserem Beispiel sind Red Hat OpenShift und Kubernetes auf minishift bereitgestellt) lÀuft, wird dieses Dashboard mit dem folgenden Befehl gestartet:

open "$(minishift openshift service grafana -u)\/d\/1\/istio-dashboard?refresh=5⩝Id=1"

Das Grafana-Dashboard ermöglicht eine schnelle Bewertung der Systemleistung. Ein Ausschnitt dieses Dashboards ist im folgenden Bild dargestellt:

Tracing und Monitoring in Istio: Mikrodienste und das Prinzip der Unbestimmtheit
Hier ist zu sehen, dass der Mikrodienst customer den Mikrodienst preference v1 aufruft, der wiederum die Mikrodienste recommendation v1 und v2 aufruft. Auf dem Grafana-Dashboard gibt es einen Block Dashboard Row fĂŒr High-Level-Kennzahlen, wie die Gesamtanzahl der Anfragen (Global Request Volume), die Erfolgsquote (success rates) und Fehler 4xx. DarĂŒber hinaus gibt es eine Server Mesh-Darstellung mit Diagrammen fĂŒr jeden Dienst sowie einen Block Services Row, um detaillierte Informationen zu jedem Container fĂŒr jeden Dienst anzuzeigen.

Jetzt gehen wir tiefer.

Bei einer gut konfigurierten Istio-Tracing, was sprichwörtlich aus der Box heraus ermöglicht, in die Analyse der Systemleistung einzutauchen. Im Jaeger-UI können Sie die Traces einsehen und sehen, wie weit und tief sie gehen, sowie visuell EngpÀsse in der Leistung lokalisieren. Bei der Verwendung von Red Hat OpenShift auf der Plattform minishift starten Sie die Jaeger-UI mit folgendem Befehl:

minishift openshift service jaeger-query --in-browser

Tracing und Monitoring in Istio: Mikrodienste und das Prinzip der Unbestimmtheit
Was kann man ĂŒber das Tracing in diesem Screenshot sagen:

  • Es unterteilt sich in 7 Spans.
  • Die Gesamtdauer betrĂ€gt 6,99 ms.
  • Der Mikrodienst recommendation, der der letzte in der Kette ist, benötigt 0,69 ms.

Diagramme dieser Art helfen schnell zu verstehen, wenn die Leistung des gesamten Systems wegen eines unwichtigen nicht funktionierenden Dienstes leidet.

Und jetzt erschweren wir die Aufgabe und starten zwei Exemplare des Mikrodienstes recommendation:v2 mit dem Befehl oc scale —replicas=2 deployment/recommendation-v2. So sehen unsere Pods danach aus:

Tracing und Monitoring in Istio: Mikrodienste und das Prinzip der Unbestimmtheit
Wenn wir jetzt wieder zu Jaeger wechseln und den Span fĂŒr den Dienst recommendation aufklappen, sehen wir, auf welchen Pod die Anfragen weitergeleitet werden. So können wir EngpĂ€sse auf der Ebene eines bestimmten Pods leicht lokalisieren. Dabei sollten wir auf das Feld node_id achten:

Tracing und Monitoring in Istio: Mikrodienste und das Prinzip der Unbestimmtheit

Wohin und wie alles lÀuft

Jetzt gehen wir in die BenutzeroberflĂ€che von Prometheus und wie zu erwarten sehen wir dort, dass die Anfragen zwischen der zweiten und der ersten Version des Dienstes recommendation im VerhĂ€ltnis 2:1 geteilt werden, streng nach der Anzahl der laufenden Pods. Zudem wird dieses Diagramm dynamisch bei der Skalierung der Pods nach oben und unten variieren, was besonders nĂŒtzlich sein wird beim Canary Deployment (wir werden dieses Bereitstellungsschema beim nĂ€chsten Mal ausfĂŒhrlicher betrachten).

Tracing und Monitoring in Istio: Mikrodienste und das Prinzip der Unbestimmtheit

Alles fÀngt gerade erst an.

TatsĂ€chlich haben wir heute nur einen kleinen Auszug aus der FĂŒlle nĂŒtzlicher Informationen ĂŒber Jaeger, Grafana und Prometheus behandelt. Das war im Grunde genommen unser Ziel – Ihnen eine Orientierung zu geben und die Perspektiven von Istio zu eröffnen.

Und denken Sie daran, all das ist bereits in Istio integriert. Bei der Verwendung bestimmter Programmiersprachen (zum Beispiel Java) und Frameworks (wie Spring Boot) lĂ€sst sich das alles umsetzen, ohne den Code der Anwendungen anzufassen. Ja, der Code muss leicht modifiziert werden, wenn Sie andere Sprachen verwenden, insbesondere Nodejs oder C#. Da jedoch die RĂŒckverfolgbarkeit (sprich „Tracing“) eine der Grundvoraussetzungen beim Aufbau zuverlĂ€ssiger Cloud-Systeme ist, mĂŒssen Sie in jedem Fall den Code anpassen, unabhĂ€ngig davon, ob Sie Istio verwenden oder nicht. Warum also nicht die MĂŒhe sinnvoller einsetzen?

Mindestens um immer mit 100%iger Sicherheit auf die Fragen „Wo?“ und „Wie schnell?“ antworten zu können.

Chaos-Engineering in Istio: So war es geplant

Die FĂ€higkeit, Dinge kaputt zu machen, hilft dabei, sicherzustellen, dass sie nicht kaputt gehen.

Softwaretests sind nicht nur komplex, sondern auch wichtig. Gleichzeitig ist die ÜberprĂŒfung der Korrektheit (ob eine Funktion das richtige Ergebnis zurĂŒckgibt) eine Sache, wĂ€hrend das Testen unter unsicheren Netzwerkbedingungen eine ganz andere Herausforderung darstellt (oft wird angenommen, dass das Netzwerk stets zuverlĂ€ssig funktioniert, was eines der acht MissverstĂ€ndnisse ĂŒber verteilte Berechnungen ist). Eine der Schwierigkeiten bei der Lösung dieser Aufgabe besteht darin, wie man AusfĂ€lle im System simuliert oder absichtlich einfĂŒhrt, indem man sogenanntes Fault Injection durchfĂŒhrt. Dies kann durch Modifikation des Quellcodes der Anwendung geschehen. Aber dann testen Sie nicht mehr Ihren ursprĂŒnglichen Code, sondern eine Version, die absichtlich AusfĂ€lle simuliert. In der Folge riskieren Sie, in die tödlichen Umarmungen von Fault Injection zu geraten und auf Geisterfehler zu stoßen – Fehler, die bei dem Versuch verschwinden, sie zu entdecken.

Jetzt zeigen wir Ihnen, wie Istio dabei hilft, diese Herausforderungen einfach zu bewÀltigen.

So sieht alles aus, wenn alles perfekt funktioniert.

Betrachten wir das folgende Szenario: Wir haben zwei Pods fĂŒr unseren Mikrodienst zur Empfehlung, den wir aus dem Istio-Leitfaden entnommen haben. Ein Pod ist als v1 gekennzeichnet, der andere als v2. Wie zu sehen ist, funktioniert bisher alles einwandfrei.

Tracing und Monitoring in Istio: Mikrodienste und das Prinzip der Unbestimmtheit
(Übrigens ist die Zahl rechts einfach ein ZĂ€hler fĂŒr die Aufrufe jedes Pods)

Aber das ist nicht das, was wir brauchen, oder? Nun, lasst uns versuchen, alles zu brechen, ohne den Quellcode zu berĂŒhren.

Wir verursachen Unterbrechungen im Microservice

Nachfolgend finden Sie die yaml-Datei fĂŒr die Istio-Routingregel, die in der HĂ€lfte der FĂ€lle fehlschlagen wird (Fehler Server 503):

Tracing und Monitoring in Istio: Mikrodienste und das Prinzip der Unbestimmtheit
Bitte beachten Sie, dass wir ausdrĂŒcklich festlegen, dass in der HĂ€lfte der FĂ€lle ein Fehler 503 zurĂŒckgegeben werden soll.

So wĂŒrde ein Screenshot des in einer Schleife laufenden curl-Befehls aussehen, nachdem wir diese Regel aktiviert haben, um AusfĂ€lle zu simulieren. Wie wir sehen, geben die HĂ€lfte der Anfragen einen Fehler 503 zurĂŒck, unabhĂ€ngig davon, an welchen Pod – v1 oder v2 – sie gesendet werden:

Tracing und Monitoring in Istio: Mikrodienste und das Prinzip der Unbestimmtheit
Um den normalen Betrieb wiederherzustellen, reicht es aus, diese Regel zu löschen, in unserem Fall mit dem Befehl istioctl delete routerule recommendation-503 -n tutorial. Hier ist Tutorial der Name des Red Hat OpenShift-Projekts, in dem unser Istio-Lehrbuch arbeitet.

Wir fĂŒhren kĂŒnstliche Verzögerungen ein

KĂŒnstliche Fehler 503 helfen, das System auf Fehlertoleranz zu testen, aber die FĂ€higkeit, Verzögerungen vorherzusagen und zu handhaben, sollte Sie noch mehr beeindrucken. TatsĂ€chlich treten Verzögerungen im echten Leben hĂ€ufiger auf als AusfĂ€lle. Ein langsamer Microservice ist ein Kernproblem, das das gesamte System belastet. Mit Istio können wir den Code, der fĂŒr die Verarbeitung von Verzögerungen zustĂ€ndig ist, testen, ohne ihn dabei zu Ă€ndern. Zu Beginn zeigen wir, wie dies bei kĂŒnstlich eingefĂŒhrten Netzwerkverzögerungen funktioniert.

Bitte beachten Sie, dass Sie nach solchen Tests möglicherweise Ihren Code ĂŒberarbeiten mĂŒssen (oder möchten). Die gute Nachricht ist, dass Sie in diesem Fall proaktiv und nicht reaktiv handeln. Genau so sollte der Entwicklungszyklus aufgebaut sein: Codierung-Testen-Feedback-Codierung-Testen


So sieht die Regel aus, die... Aber wissen Sie was? Istio ist so einfach, und diese yaml-Datei ist so klar, dass in diesem Beispiel alles fĂŒr sich selbst spricht, schauen Sie einfach:

Tracing und Monitoring in Istio: Mikrodienste und das Prinzip der Unbestimmtheit
In der HĂ€lfte der FĂ€lle wird es eine Verzögerung von 7 Sekunden geben. Und das ist nicht dasselbe, als hĂ€tten wir einen sleep-Befehl in den Quellcode eingefĂŒgt, da Istio die Anfrage tatsĂ€chlich um 7 Sekunden verzögert. Da Istio die Jaeger-Traceability unterstĂŒtzt, ist diese Verzögerung deutlich im Jaeger-UI zu beobachten, wie im Screenshot unten gezeigt. Beachten Sie die lange Anfrage in der oberen rechten Ecke des Diagramms – ihre Dauer betrĂ€gt 7,02 Sekunden:

Tracing und Monitoring in Istio: Mikrodienste und das Prinzip der Unbestimmtheit
Dieses Szenario ermöglicht es uns, den Code unter Bedingungen mit Netzwerkverzögerungen zu testen. Und es ist klar, dass wir, wenn wir diese Regel entfernen, die kĂŒnstliche Verzögerung beseitigen werden. Lassen Sie uns wiederholen: Wir haben all das getan, ohne den Quellcode zu berĂŒhren.

Nicht aufgeben und nicht nachlassen

Eine weitere nĂŒtzliche Funktion von Istio fĂŒr Chaos-Engineering ist die mehrfache Anfrage an den Dienst, eine vorgegebene Anzahl von Versuchen. Der Sinn hierbei ist, die Versuche nicht abzubrechen, wenn die erste Anfrage mit einem Fehler 503 endet – und vielleicht haben wir beim N-ten Versuch GlĂŒck. Vielleicht hat der Dienst aus irgendeinem Grund nur kurz pausiert. Ja, dies ist ein Grund, den wir herausfinden und beheben sollten. Aber das spĂ€ter, jetzt versuchen wir, die SystemfunktionalitĂ€t aufrechtzuerhalten.

Wir möchten also, dass der Dienst von Zeit zu Zeit einen Fehler 503 ausgibt, und Istio soll danach versuchen, erneut eine Verbindung herzustellen. Und dafĂŒr brauchen wir offensichtlich einen Weg, um einen Fehler 503 zu erzeugen, ohne den eigentlichen Code zu berĂŒhren


Halt, warte! Das haben wir doch gerade gemacht.

Diese Datei sorgt dafĂŒr, dass der Dienst recommendation-v2 in der HĂ€lfte der FĂ€lle einen Fehler 503 ausgibt:

Tracing und Monitoring in Istio: Mikrodienste und das Prinzip der Unbestimmtheit
Es ist offensichtlich, dass einige Anfragen fehlschlagen werden:

Tracing und Monitoring in Istio: Mikrodienste und das Prinzip der Unbestimmtheit
Jetzt aktivieren wir die Istio-Funktion Retry:

Tracing und Monitoring in Istio: Mikrodienste und das Prinzip der Unbestimmtheit
Diese Routing-Regel macht drei Wiederholungen mit einem Intervall von zwei Sekunden und sollte die Fehler 503 reduzieren (und idealerweise ganz beseitigen):

Tracing und Monitoring in Istio: Mikrodienste und das Prinzip der Unbestimmtheit
Zusammenfassend haben wir Istio so konfiguriert, dass es erstens einen Fehler 503 fĂŒr die HĂ€lfte der Anfragen generiert. Zweitens fĂŒhrt Istio bei einem Fehler 503 drei Versuche durch, erneut mit dem Dienst zu verbinden. Das Ergebnis ist, dass alles hervorragend funktioniert. So haben wir mit der Retry-Funktion unser Versprechen gehalten, nicht aufzugeben und nicht nachzulassen.

Und ja, wir haben es wieder getan, ohne den Code zu berĂŒhren. Alles, was wir brauchten, waren zwei Istio-Routing-Regeln:

Tracing und Monitoring in Istio: Mikrodienste und das Prinzip der Unbestimmtheit

Wie man den Benutzer nicht im Stich lÀsst oder sieben auf einen Schlag warten lÀsst.

Und jetzt drehen wir die Situation um und betrachten das Szenario, in dem man nur fĂŒr eine bestimmte Zeit nicht zurĂŒckweichen und nicht aufgeben sollte. Danach muss man einfach versuchen, die Anfrage nicht weiter zu bearbeiten, um nicht alle zum Warten auf einen langsamen Dienst zu zwingen. Anders gesagt, wir werden die verlorene Position nicht verteidigen, sondern uns auf eine sichere Linie zurĂŒckziehen, um den Webseitenbesucher nicht im Ungewissen zu lassen.

In Istio kann man ein Zeitlimit fĂŒr die AusfĂŒhrung von Anfragen festlegen. Wenn der Dienst dieses Zeitlimit ĂŒberschreitet, wird ein Fehler 504 (Gateway Timeout) zurĂŒckgegeben – das geschieht wiederum alles ĂŒber die Istio-Konfiguration. Wir mĂŒssen jedoch im Quellcode des Dienstes einen sleep-Befehl hinzufĂŒgen (und dann natĂŒrlich ein rebuild und redeploy durchfĂŒhren), um eine langsame Verarbeitung des Dienstes zu simulieren. Leider ist es anders nicht möglich.

Also haben wir einen dreisekĂŒndigen sleep in den Code des recommendation v2-Dienstes eingefĂŒgt, das entsprechende Image neu gebaut und den Container redeployt. Nun werden wir ein Zeitlimit mit folgender Istio-Routingregel hinzufĂŒgen:

Tracing und Monitoring in Istio: Mikrodienste und das Prinzip der Unbestimmtheit
Auf dem obigen Screenshot sieht man, dass wir die Versuche, mit dem recommendation-Dienst zu kommunizieren, abbrechen, wenn wir innerhalb einer Sekunde keine Antwort erhalten, also noch bevor der Fehler 504 auftritt. Nach der Anwendung dieser Routingregel (und der HinzufĂŒgung des dreisekĂŒndigen sleep im Code des recommendation:v2-Dienstes) erhalten wir Folgendes:

Tracing und Monitoring in Istio: Mikrodienste und das Prinzip der Unbestimmtheit
Wir wiederholen uns, aber das Zeitlimit kann gesetzt werden, ohne den Quellcode zu berĂŒhren. Ein zusĂ€tzlicher Vorteil hierbei ist, dass Sie jetzt Ihren Code so modifizieren können, dass er auf das Zeitlimit reagiert, und diese Anpassungen problemlos mit Hilfe von Istio testen können.

Und jetzt alles zusammen

Ein wenig Chaos mit Hilfe von Istio einbringen – das ist eine großartige Möglichkeit, Ihren Code und die ZuverlĂ€ssigkeit Ihres Systems insgesamt zu testen. Fallback-, Bulkhead- und Circuit-Breaker-Muster, Mechanismen zur Erzeugung kĂŒnstlicher AusfĂ€lle und Verzögerungen sowie Wiederholungsanrufe und Zeitlimits sind sehr nĂŒtzlich beim Erstellen von ausfallsicheren Cloud-Systemen. In Kombination mit Kubernetes und Red Hat OpenShift werden diese Werkzeuge Ihnen helfen, die Zukunft mit Zuversicht zu begegnen.

Quelle: habr.com

60GB SSD 8Gb DDR4