Istio Circuit Breaker: Unterbrochene Behälter trennen

Die Ferien sind vorbei und wir kehren mit unserem zweiten Beitrag in der Istio Service Mesh Serie zurück.



Das heutige Thema ist Leistungsschalter, was auf Russisch als elektrotechnisch übersetzt "Leistungsschalter", in der gemeinsamen Sprache "Leistungsschalter" bedeutet. Nur in Istio trennt diese Maschine keine kurzgeschlossenen oder überlasteten Stromkreise, sondern fehlerhafte Behälter.

Wie es im Idealfall funktionieren sollte


Wenn Microservices beispielsweise von Kubernetes als Teil der OpenShift-Plattform verwaltet werden, werden sie je nach Auslastung automatisch vergrößert und verkleinert. Da Microservices in Pods arbeiten, kann es an einem Endpunkt mehrere Instanzen von containerisierten Microservices geben, und Kubernetes leitet Anforderungen weiter und verteilt die Last zwischen ihnen. Und im Idealfall sollte das alles perfekt funktionieren.

Wir erinnern uns, dass Microservices klein und kurzlebig sind. Die Vergänglichkeit, die hier die Einfachheit der Entstehung und des Verschwindens bedeutet, wird oft unterschätzt. Die Geburt und der Tod der nächsten Instanz von Microservice im Pod werden erwartet, OpenShift und Kubernetes machen das gut und alles funktioniert großartig - aber auch in der Theorie.

Wie funktioniert das wirklich?


Stellen Sie sich nun vor, dass eine bestimmte Instanz des Mikrodienstes, dh der Container, unbrauchbar geworden ist: Entweder reagiert er nicht (Fehler 503) oder, was unangenehmer ist, reagiert er, aber zu langsam. Mit anderen Worten, es wird stummgeschaltet oder es wird nicht auf Anforderungen geantwortet, es wird jedoch nicht automatisch aus dem Pool entfernt. Was ist in diesem Fall zu tun? Nochmal versuchen? Entfernen Sie es aus dem Routing-Schema? Und was bedeutet "zu langsam" - wie viel ist es in Zahlen und wer bestimmt sie? Vielleicht gib ihm einfach eine Pause und versuche es später? Wenn ja, wie viel später?

Was ist Pool Ejection in Istio


Und hier kommt Istio mit seinen Leistungsschaltern zur Hilfe, die vorübergehend fehlerhafte Container aus dem Pool der Routing- und Lastausgleichsressourcen entfernen und das Pool-Ejection-Verfahren implementieren.

Mithilfe einer Ausreißererkennungsstrategie erkennt Istio Pod-Kurven, die aus der allgemeinen Reihe entfernt wurden, und entfernt sie für einen bestimmten Zeitraum aus dem Ressourcenpool, dem so genannten „Schlaffenster“.

Um zu zeigen, wie dies in Kubernetes auf der OpenShift-Plattform funktioniert, beginnen wir mit einem Screenshot der normalerweise funktionierenden Microservices aus dem Beispiel im Red Hat Developer Demos- Repository. Hier haben wir zwei Pods, v1 und v2, in denen jeweils ein Container funktioniert. Wenn die Routing-Regeln von Istio nicht verwendet werden, wendet Kubernetes standardmäßig ein gleichmäßig ausgeglichenes Round-Robin-Routing an:


Bereit für einen Absturz


Vor dem Pool Ejection müssen Sie eine Istio-Routing-Regel erstellen. Angenommen, wir möchten Anfragen in Bezug auf 50/50 auf mehrere Pods verteilen. Außerdem werden wir die Anzahl der v2-Container von eins auf zwei erhöhen:

oc scale deployment recommendation-v2 --replicas=2 -n tutorial 

Nun definieren wir eine Routing-Regel, damit der Datenverkehr im Verhältnis 50/50 auf die Pods verteilt wird.


Und hier ist das Ergebnis dieser Regel:


Es ist möglich zu bemängeln, dass auf diesem Bildschirm nicht 50/50, sondern 14: 9 angezeigt wird, aber mit der Zeit wird sich die Situation verbessern.

Wir arrangieren einen Fehler


Und jetzt deaktivieren wir einen der beiden Container der Version 2, sodass wir einen fehlerfreien Container der Version 1, einen fehlerfreien Container der Version 2 und einen fehlerhaften Container der Version 2 haben:


Beheben Sie den Absturz


Wir haben also einen fehlerhaften Behälter und es ist Zeit für den Poolauswurf. Mit einer sehr einfachen Konfiguration schließen wir diesen fehlerhaften Container für 15 Sekunden von Routing-Schemata aus, in der Erwartung, dass er in einen fehlerfreien Zustand zurückkehrt (entweder wird er neu gestartet oder die Leistung wird wiederhergestellt). So sieht diese Konfiguration aus und die Ergebnisse ihrer Arbeit:



Wie Sie sehen, wird der ausgefallene Container v2 beim Weiterleiten von Anforderungen nicht mehr verwendet, da er aus dem Pool entfernt wurde. Nach 15 Sekunden kehrt es automatisch zum Pool zurück. Eigentlich haben wir nur gezeigt, wie Pool Ejection funktioniert.

Fangen Sie an, Architektur zu bauen


In Kombination mit den Überwachungsfunktionen von Istio können Sie mit der Erstellung eines Frameworks für das automatische Ersetzen fehlerhafter Container beginnen, um Ausfallzeiten und Abstürze zu reduzieren oder sogar zu vermeiden.

Die NASA hat ein hochkarätiges Motto - Failure Is Not a Option, verfasst von Flugdirektor Gene Krantz . Es kann ins Russische übersetzt werden als "Niederlage ist keine Option", und der Punkt hier ist, dass alles so gemacht werden kann, dass es mit genügend Willen funktioniert. Im wirklichen Leben passieren Fehler jedoch nicht nur, sie sind überall und in allem unvermeidlich. Und wie geht man bei Microservices damit um? Unserer Meinung nach ist es besser, sich nicht auf Willenskraft zu verlassen, sondern auf die Fähigkeiten von Containern, Kubernetes , Red Hat OpenShift und Istio .

Istio setzt, wie wir oben geschrieben haben, das Konzept der Leistungsschalter um, das sich in der physischen Welt bewährt hat. Und genau wie ein Automat einen problematischen Teil eines Stromkreises trennt der Software-Leistungsschalter in Istio die Verbindung zwischen dem Anforderungsfluss und dem Problemcontainer, wenn am Endpunkt etwas nicht stimmt, z. B. wenn der Server abstürzt oder langsamer wird.

Darüber hinaus treten im zweiten Fall nur weitere Probleme auf, da die Bremsen eines Containers nicht nur eine Kaskade von Verzögerungen beim Zugriff auf die Dienste verursachen und infolgedessen die Leistung des gesamten Systems verringern, sondern auch wiederholte Anforderungen an den bereits langsam laufenden Dienst verursachen, was die Situation nur verschärft .

Leistungsschalter in der Theorie


Leistungsschalter ist ein Proxy, der den Fluss von Anforderungen an den Endpunkt steuert. Wenn dieser Punkt nicht mehr funktioniert oder je nach Einstellung langsamer wird, trennt sich der Proxy vom Container. Der Datenverkehr wird dann auf andere Container umgeleitet, und zwar nur aufgrund des Lastenausgleichs. Die Verbindung bleibt für ein bestimmtes Schlaffenster (z. B. zwei Minuten) offen (offen) und wird dann als halb offen (halb offen) betrachtet. Der Versuch, die nächste Anforderung zu senden, bestimmt den weiteren Kommunikationsstatus. Wenn mit dem Dienst alles in Ordnung ist, kehrt die Verbindung in den Betriebszustand zurück und wird wieder geschlossen. Wenn mit dem Dienst immer noch etwas nicht stimmt, wird die Verbindung geöffnet und das Schlaffenster wird wieder aktiviert. So sieht das vereinfachte Leistungsschalter-Zustandsdiagramm aus:


Hierbei ist zu beachten, dass dies alles sozusagen auf der Ebene der Systemarchitektur geschieht. Daher müssen Sie Ihren Anwendungen irgendwann das Arbeiten mit dem Leistungsschalter beibringen, z. B. als Antwort einen Standardwert bereitstellen oder, falls möglich, die Existenz des Dienstes ignorieren. Hierfür wird ein Schottmuster verwendet, das jedoch den Rahmen dieses Artikels sprengt.

Leistungsschalter in der Praxis


Zum Beispiel werden wir auf OpenShift zwei Versionen unseres Microsoft-Empfehlungsdienstes starten. Version 1 wird gut funktionieren, aber in Version 2 werden wir eine Verzögerung einbauen, um die Bremsen auf dem Server zu simulieren. Verwenden Sie das Belagerungstool , um die Ergebnisse anzuzeigen:

 siege -r 2 -c 20 -v customer-tutorial.$(minishift ip).nip.io 


Alles scheint zu funktionieren, aber zu welchem ​​Preis? Auf den ersten Blick haben wir eine Verfügbarkeit von 100%, aber schauen Sie genauer hin - die maximale Transaktionsdauer beträgt 12 Sekunden. Dies ist eindeutig ein Engpass und muss gestickt werden.

Dazu verwenden wir Istio, um den Zugriff auf langsame Container zu verhindern. So sieht die entsprechende Konfiguration mit dem Leistungsschalter aus:


Die letzte Zeile mit dem Parameter httpMaxRequestsPerConnection gibt an, dass die Verbindung mit geöffnet werden soll, wenn versucht wird, eine weitere - die zweite - Verbindung zusätzlich zu der vorhandenen zu erstellen. Da unser Container einen Bremsdienst imitiert, treten solche Situationen in regelmäßigen Abständen auf, und Istio gibt einen 503-Fehler zurück. Die Belagerung zeigt Folgendes:


OK, wir haben Leistungsschalter, was kommt als nächstes?


Deshalb haben wir ein automatisches Herunterfahren implementiert, ohne den Quellcode der Dienste selbst zu berühren. Mithilfe des oben beschriebenen Verfahrens zum Ausschalten des Leistungsschalters und des Pools können wir die Bremsbehälter aus dem Ressourcenpool entfernen, bis sie wieder normal sind, und ihren Status mit einer bestimmten Häufigkeit überprüfen - in unserem Beispiel sind dies zwei Minuten (Parameter sleepWindow).

Beachten Sie, dass die Fähigkeit der Anwendung, auf Fehler 503 zu reagieren, immer noch auf der Ebene ihres Quellcodes festgelegt ist. Es gibt viele Strategien für die Arbeit mit Leistungsschaltern, die je nach Situation angewendet werden.

Im nächsten Beitrag werden wir uns mit Tracing und Monitoring befassen, die bereits integriert sind oder leicht zu Istio hinzugefügt werden können, sowie mit dem absichtlichen Einfügen von Fehlern in das System.

Source: https://habr.com/ru/post/de483262/


All Articles