Das Heisenbergsche Unschärfeprinzip besagt, dass man die Position eines Objekts und seine Geschwindigkeit nicht gleichzeitig messen kann. Bewegt sich das Objekt, hat es keinen festen Standort. Ist ein Standort vorhanden, bedeutet das, dass es keine Geschwindigkeit hat.

In Bezug auf Microservices auf der Red Hat OpenShift-Plattform (und verwaltet von Kubernetes) können sie dank entsprechender Open-Source-Software gleichzeitig ihre Leistung und Funktionsfähigkeit melden. Das widerlegt zwar nicht Heisenberg, beseitigt jedoch die Unsicherheit im Umgang mit Cloud-Anwendungen. Istio ermöglicht eine einfache Organisation von Trace- und Monitoring-Funktionen für solche Anwendungen, um alles im Blick zu behalten.
Lass uns über Terminologie entscheiden
Unter Tracing (Tracing) Wir verstehen die Protokollierung systemischer Aktivitäten. Das klingt zwar recht allgemein, aber die wichtigste Regel hier ist, dass die Trace-Daten in das entsprechende Speicherformat zurückgegeben werden, ohne sich um deren Formatierung zu kümmern. Die gesamte Arbeit der Datensuche und -analyse obliegt ihren Nutzern. In Istio wird das Tracing-System Jaeger verwendet, das das OpenTracing-Datenmodell implementiert.
Traces (Traces, und das Wort „Traces“ wird hier im Sinne von „Spuren“ verwendet, ähnlich wie in der ballistischen Analyse) nennen wir die Daten, die den Verlauf einer Anfrage oder einer Arbeitseinheit vollständig beschreiben, wie man so schön sagt, „von Anfang bis Ende“. Zum Beispiel alles, was passiert, ab dem Moment, in dem ein Benutzer auf eine Schaltfläche auf der Webseite klickt, bis zur Rückgabe der Daten, einschließlich aller beteiligten Mikrodienste. Man kann sagen, dass ein Trace den gesamten Verlauf einer Anfrage hin und zurück vollständig beschreibt (oder modelliert). Im Jaeger-Interface werden die Traces zeitlich aufgeschlüsselt, ähnlich wie man eine Kette in ihre einzelnen Glieder zerlegen kann. Nur dass anstelle der Glieder ein Trace aus sogenannten Spans besteht.
Span – ist der Zeitraum vom Beginn der Ausführung einer Arbeitseinheit bis zu ihrem Abschluss. In dieser Analogie kann man sagen, dass jeder Span ein einzelnes Glied in der Kette darstellt. Ein Span kann (oder kann nicht) einen oder mehrere untergeordnete Spans haben. Folglich wird der oberste Span (Root Span) die gleiche Gesamtdauer haben wie der Trace, auf den er sich bezieht.
Überwachung – ist eigentlich die Überwachung Ihres Systems – mit eigenen Augen, über die UI oder durch Automatisierungstools. Dem Monitoring liegen Trace-Daten zugrunde. In Istio wird das Monitoring durch Prometheus realisiert und hat eine entsprechende UI. Prometheus unterstützt die automatische Überwachung mithilfe von Alerts und Alert Managern.
Wir machen Striche
Um die Tracing-Funktionalität zu ermöglichen, muss die Anwendung eine Sammlung von Spans erstellen. Diese müssen dann an Jaeger exportiert werden, damit ein visuelles Tracing-Diagramm erstellt werden kann. Unter anderem kennzeichnen diese Spans den Namen der Operation sowie die Zeitstempel für ihren Beginn und Abschluss. Der Transfer der Spans erfolgt durch die Umleitung der für Jaeger bestimmten HTTP-Header von eingehenden Anfragen zu ausgehenden Anfragen. Je nach verwendeter Programmiersprache kann dies geringfügige Anpassungen des Quellcodes der Anwendungen erfordern. Im Folgenden ist ein Beispielcode in Java (unter Verwendung des Spring Boot-Frameworks) angegeben, der B3-Header (Zipkin-Stil) zu Ihrer Anfrage im Konfigurationsklasse von Spring hinzufügt:

Dabei werden die folgenden Header-Einstellungen verwendet:

Wenn Sie Java verwenden, müssen Sie den Code nicht ändern, sondern lediglich einige Zeilen zur POM-Datei von Maven hinzufügen und Umgebungsvariablen festlegen. Hier sind die Zeilen, die in die POM.XML-Datei eingefügt werden müssen, um den Jaeger Tracer Resolver zu integrieren:

Die entsprechenden Umgebungsvariablen werden im Dockerfile festgelegt:

Alles klar, jetzt ist alles eingerichtet und unsere Mikrodienste beginnen, Tracedaten zu generieren.
Wir schauen uns das im Großen und Ganzen an
Istio beinhaltet ein einfaches Dashboard auf Basis von Grafana. Wenn alles konfiguriert ist und auf der Red Hat OpenShift PaaS-Plattform läuft (in unserem Beispiel sind Red Hat OpenShift und Kubernetes auf Minishift bereitgestellt), wird dieses Dashboard mit folgendem 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 in der Abbildung unten dargestellt:

Hier sieht man, dass der Mikrodienst customer den Mikrodienst preference v1 aufruft, und dieser wiederum ruft die Mikrodienste recommendation v1 und v2 auf. Im Grafana-Dashboard gibt es einen Bereich Dashboard Row für hochrangige Metriken wie das Gesamtanfragevolumen (Global Request Volume), die Erfolgsquote (success rates) und 4xx-Fehler. Darüber hinaus gibt es eine Ansicht Server Mesh mit Grafiken für jeden Dienst und einen Bereich Services Row zur Anzeige detaillierter Informationen zu jedem Container für jeden Dienst.
Jetzt tauchen wir tiefer ein
Mit einer korrekt konfigurierten Istio-Tracierung kann man direkt out of the box tiefgehende Leistungsanalysen des Systems durchführen. Im Jaeger-UI können Tracierungen betrachtet werden, um zu sehen, wie weit und tief sie reichen, sowie um Engpässe in der Leistung visuell zu identifizieren. 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

Was kann man über die Tracierung auf diesem Screenshot sagen:
- Sie besteht aus 7 Spans.
- Die Gesamtzeit beträgt 6,99 ms.
- Der Microservice recommendation, der der letzte in der Kette ist, benötigt 0,69 ms.
Diagramme dieser Art ermöglichen es, schnell zu erkennen, wenn die Leistung des gesamten Systems aufgrund eines nicht einwandfrei funktionierenden Dienstes leidet.
Und jetzt erschweren wir die Aufgabe, indem wir zwei Instanzen des Microservices recommendation:v2 mit dem Befehl oc scale --replicas=2 deployment/recommendation-v2 starten. So sehen unsere Pods danach aus:

Wenn wir jetzt zu Jaeger zurückwechseln und den Span für den Service recommendation aufklappen, sehen wir, welcher Pod die Anfragen verarbeitet. So können wir problemlos die Verzögerungen auf der Ebene eines bestimmten Pods lokalisieren. Dabei sollten wir auf das Feld node_id achten:

Wohin und wie alles läuft
Jetzt gehen wir in die Benutzeroberfläche von Prometheus und sehen erwartungsgemäß, dass die Anfragen zwischen der zweiten und der ersten Version des Services recommendation im Verhältnis 2:1 aufgeteilt sind, genau nach der Anzahl der aktiven Pods. Dieser Graph wird sich dynamisch ändern, wenn die Pods nach oben oder unten skaliert werden, was besonders nützlich beim Canary Deployment sein wird (wir werden dieses Bereitstellungsschema beim nächsten Mal ausführlicher betrachten).

Alles fängt gerade erst an
Tatsächlich haben wir heute, sozusagen, nur einen kleinen Einblick in den reichen Fundus an Informationen zu Jaeger, Grafana und Prometheus gegeben. Das war im Grunde auch unser Ziel – Sie in die richtige Richtung zu leiten und die Perspektiven von Istio zu eröffnen.
Und denken Sie daran, dass all dies bereits in Istio integriert ist. Bei der Verwendung bestimmter Programmiersprachen (wie Java) und Frameworks (wie Spring Boot) kann all dies umgesetzt werden, ohne den Anwendungscode berühren zu müssen. Ja, der Code muss leicht modifiziert werden, wenn Sie andere Sprachen verwenden, insbesondere Node.js oder C#. Aber da Nachverfolgbarkeit (lesen Sie "Tracing") eine der Voraussetzungen für den Aufbau zuverlässiger Cloud-Systeme ist, müssen Sie den Code in jedem Fall anpassen, ob Sie Istio nutzen oder nicht. Warum also nicht die Anstrengungen sinnvoller nutzen?
Mindestens um immer die Fragen „wo?“ und „wie schnell?“ mit 100%iger Sicherheit zu beantworten.
Chaos-Engineering in Istio: So war es gedacht
Die Fähigkeit, Dinge kaputt zu machen, hilft dabei, sicherzustellen, dass sie nicht kaputtgehen.
Die Software-Testung ist nicht nur eine komplizierte, sondern auch eine wichtige Aufgabe. Gleichzeitig ist die Überprüfung auf Korrektheit (zum Beispiel ob eine Funktion das richtige Ergebnis zurückgibt) das eine, während das Testen unter Bedingungen eines unzuverlässigen Netzwerks eine ganz andere Herausforderung darstellt (oft wird angenommen, dass das Netzwerk immer ohne Störungen funktioniert, und das ist die häufigste von acht Fehleinschätzungen im Bereich der verteilten Berechnungen). Eine der Schwierigkeiten bei der Lösung dieser Problematik liegt darin, wie man Systemausfälle simuliert oder absichtlich einführt, was als Fault Injection bezeichnet wird. Dies kann durch die Modifikation des Quellcodes der Anwendung erfolgen. Doch dann testen Sie nicht Ihren ursprünglichen Code, sondern eine Version, die speziell Ausfälle simuliert. Infolgedessen riskieren Sie, in die tödlichen Umarmungen der Fault Injection zu geraten und auf Geisterfehler zu stoßen – Fehler, die beim Versuch, sie zu erkennen, verschwinden.
Nun werden wir zeigen, wie Istio hilft, diese Herausforderungen schnell zu bewältigen.
So sieht alles aus, wenn alles perfekt läuft.
Betrachten wir folgendes Szenario: Wir haben zwei Pods für unseren Microservice Recommendation, den wir aus einem Istio-Lehrbuch entnommen haben. Ein Pod ist als v1 gekennzeichnet, der andere als v2. Wie zu sehen ist, funktioniert alles hervorragend.

(Übrigens: Die Zahl rechts ist einfach ein Zähler für jeden Pod.)
Aber das ist nicht das, was wir wollen, oder? Lassen Sie uns versuchen, alles kaputt zu machen, ohne den Quellcode zu berühren.
Wir erzeugen Ausfälle im Microservice
Nachfolgend finden Sie die YAML-Datei für die Istio-Routingregel, die in der Hälfte der Fälle einen Fehler erzeugt. Server 503):

Bitte beachten Sie, dass wir explizit festlegen, dass in der Hälfte der Fälle ein Fehler 503 zurückgegeben werden soll.
So würde ein Screenshot des wiederholt ausgeführten curl-Befehls aussehen, nachdem wir diese Regel aktiviert haben, um Fehler zu simulieren. Wie zu sehen ist, gibt die Hälfte der Anfragen den Fehler 503 zurück, unabhängig davon, an welchen Pod – v1 oder v2 – sie gesendet werden:

Um den normalen Betrieb wiederherzustellen, reicht es aus, diese Regel zu löschen, in unserem Fall mit dem Kommando istioctl delete routerule recommendation-503 -n tutorial. Hierbei ist Tutorial der Name des Red Hat OpenShift-Projekts, in dem unser Istio-Lehrbuch läuft.
Wir fügen künstliche Verzögerungen hinzu.
Künstliche Fehler 503 helfen dabei, das System auf Ausfallsicherheit zu testen, aber die Fähigkeit, Verzögerungen vorherzusagen und zu bewältigen, sollte Sie noch mehr beeindrucken. Tatsächlich treten Verzögerungen im echten Leben häufiger auf als Ausfälle. Ein langsam arbeitender Mikroservice ist ein Gift, unter dem das gesamte System leidet. Dank Istio können Sie den Code zur Verarbeitung von Verzögerungen testen, ohne ihn dabei zu ändern. Zunächst zeigen wir Ihnen, wie Sie dies im Fall künstlich erzeugter Netzwerkverzögerungen tun können.
Bitte beachten Sie, dass Sie nach solch einem Test eventuell (oder möglicherweise) Ihren Code überarbeiten müssen (oder möchten). Die gute Nachricht ist, dass Sie in diesem Fall proaktiv und nicht reaktiv handeln werden. So sollte der Entwicklungszyklus aufgebaut werden: Programmieren-Testen-Feedback-Programmierenn-Testen…
So sieht die Regel aus, die… Obwohl wissen Sie was? Istio ist so einfach und diese yaml-Datei ist so verständlich, dass alles in diesem Beispiel für sich selbst spricht, schauen Sie einfach einmal hin:

In der Hälfte der Fälle wird es zu einer 7-sekündigen Verzögerung kommen. Das ist keineswegs das gleiche, als würden wir im Quellcode einen sleep-Befehl einfügen, denn Istio verzögert die Anfrage tatsächlich um 7 Sekunden. Da Istio Jaeger-Tracing unterstützt, ist diese Verzögerung im Jaeger-UI gut erkennbar, wie im Screenshot unten gezeigt. Beachten Sie die lange Anfrage in der oberen rechten Ecke des Diagramms – ihre Dauer beträgt 7,02 Sekunden:

Dieses Szenario ermöglicht es, den Code unter Bedingungen mit Netzwerkverzögerungen zu testen. Und es ist klar, dass wir durch das Entfernen dieser Regel die künstliche Verzögerung beseitigen werden. Um es zu wiederholen, wir haben all dies erneut getan, ohne den Quellcode zu verändern.
Nicht zurückweichen und nicht aufgeben
Eine weitere nützliche Funktion von Istio für Chaos Engineering ist die Wiederholung von Anfragen an einen Dienst eine bestimmte Anzahl von Malen. Der Sinn dahinter ist, die Versuche nicht abzubrechen, wenn die erste Anfrage mit einem Fehler 503 endet – und vielleicht haben wir beim N-ten Mal Glück. Vielleicht hat der Dienst aus irgendeinem Grund nur kurz pausiert. Ja, diesen Grund sollten wir ergründen und beheben. Aber das können wir später klären; vorerst versuchen wir, das System am Laufen zu halten.
Also, wir wollen, dass der Dienst von Zeit zu Zeit einen Fehler 503 gibt, und Istio sollte danach versuchen, ihn erneut zu kontaktieren. Hier benötigen wir eindeutig eine Möglichkeit, einen Fehler 503 zu erzeugen, ohne den Code selbst zu berühren...
Halt, wartet! Das haben wir gerade gemacht.
Diese Datei sorgt dafür, dass der Dienst recommendation-v2 in 50 % der Fälle einen Fehler 503 zurückgibt:

Offensichtlich werden einige Anfragen fehlschlagen:

Jetzt aktivieren wir die Istio-Funktion Retry:

Diese Routing-Regel führt drei Wiederholungen mit einem Intervall von zwei Sekunden durch und sollte die Fehler 503 reduzieren (ideal wäre es, sie ganz zu entfernen):

Zusammenfassend haben wir es so eingerichtet, dass Istio erstens für die Hälfte der Anfragen einen 503-Fehler generiert. Und zweitens führt dasselbe Istio bei einem auftreten Fehler 503 drei Versuche durch, um die Verbindung zum Dienst wiederherzustellen. Das Ergebnis ist einfach ausgezeichnet. Durch die Nutzung der Retry-Funktion haben wir unser Versprechen eingehalten, nicht aufzugeben und durchzuhalten.
Ja, und wir haben es wieder getan, ohne den Code überhaupt zu berühren. Alles, was wir benötigten, waren zwei Istio-Routing-Regeln:

Wie man den Benutzer nicht enttäuscht oder sieben auf einen wartet
Jetzt kehren wir die Situation um und betrachten ein Szenario, in dem es nur für eine gewisse Zeit sinnvoll ist, nicht aufzugeben und durchzuhalten. Danach sollten wir einfach die Versuche, die Anfrage zu verarbeiten, einstellen, um nicht alle dazu zu bringen, auf einen einzigen blockierenden Dienst zu warten. Anders ausgedrückt, wir werden die verlorene Position nicht verteidigen, sondern uns auf eine Backup-Position zurückziehen, um die Benutzer der Website nicht zu enttäuschen und sie nicht in Ungewissheit zu halten.
In Istio kann ein Timeout für die Anfragebearbeitung festgelegt werden. Wenn der Dienst dieses Timeout überschreitet, wird der Fehler 504 (Gateway Timeout) zurückgegeben – das alles geschieht über die Istio-Konfiguration. Allerdings müssen wir in den Quellcode des Dienstes einen sleep-Befehl einfügen (und dann natürlich ein Rebuild und Redeploy durchführen), um die langsame Ausführung des Dienstes zu simulieren. Leider geht es nicht anders.
Also haben wir einen dreisekündigen sleep in den Code des Dienstes recommendation v2 eingefügt, das entsprechende Image neu gebaut und den Container redeployt. Jetzt fügen wir mit der folgenden Istio-Routingregel das Timeout hinzu:

Im obigen Screenshot ist zu sehen, dass wir die Verbindung zum Dienst recommendation abbrechen, wenn wir innerhalb von einer Sekunde keine Antwort erhalten, also noch bevor der Fehler 504 auftritt. Nach Anwendung dieser Routingregel (und dem Hinzufügen des dreisekündigen sleep im Code des Dienstes recommendation:v2) erhalten wir Folgendes:

Wir wiederholen uns, aber das Timeout kann festgelegt werden, ohne den Quellcode zu ändern. Ein zusätzlicher Vorteil ist, dass Sie Ihren Code jetzt so anpassen können, dass er auf das Timeout reagiert, und diese Anpassungen mit Istio problemlos testen können.
Und jetzt alles zusammen
Ein wenig Chaos mit Istio zu erzeugen, ist eine hervorragende Methode, um Ihren Code und die Zuverlässigkeit Ihres Systems insgesamt zu testen. Fallback-Vorlagen, Bulkheads und Circuit Breaker, Mechanismen zur Erzeugung von künstlichen Ausfällen und Verzögerungen sowie erneute Aufrufe und Timeouts sind äußerst nützlich beim Aufbau von ausfallsicheren Cloud-Systemen. In Kombination mit Kubernetes und Red Hat OpenShift werden diese Werkzeuge Ihnen helfen, selbstbewusst in die Zukunft zu gehen.
Quelle: habr.com
