Die Feiertage sind vorbei und wir sind zurück mit unserem zweiten Beitrag in der Istio Service Mesh-Reihe.
Das heutige Thema ist Leistungsschalter, was in der russischen Elektrotechnik „Leistungsschalter“ bedeutet, im allgemeinen Sprachgebrauch „Leistungsschalter“. Nur in Istio trennt diese Maschine nicht einen kurzgeschlossenen oder überlasteten Stromkreis, sondern defekte Behälter.
Wie das im Idealfall funktionieren sollte
Wenn Microservices von Kubernetes verwaltet werden, beispielsweise innerhalb der OpenShift-Plattform, skalieren sie je nach Auslastung automatisch nach oben und unten. Da Microservices in Pods ausgeführt werden, kann es auf einem Endpunkt mehrere Instanzen eines Container-Microservices geben, und Kubernetes leitet Anforderungen weiter und sorgt für einen Lastausgleich zwischen ihnen. Und im Idealfall sollte das alles perfekt funktionieren.
Wir erinnern uns daran, dass Microservices klein und vergänglich sind. Flüchtigkeit, also die Leichtigkeit des Erscheinens und Verschwindens, wird oft unterschätzt. Die Geburt und der Tod einer weiteren Instanz eines Microservices in einem Pod sind durchaus zu erwartende Dinge, OpenShift und Kubernetes bewältigen das gut und alles funktioniert großartig – aber wiederum theoretisch.
Wie es wirklich funktioniert
Stellen Sie sich nun vor, dass eine bestimmte Instanz eines Microservices, also eines Containers, unbrauchbar geworden ist: Entweder antwortet er nicht (Fehler 503) oder, was noch unangenehmer ist, er antwortet, aber zu langsam. Mit anderen Worten: Es kommt zu Störungen oder reagiert nicht auf Anfragen, es wird jedoch nicht automatisch aus dem Pool entfernt. Was ist in diesem Fall zu tun? Noch einmal versuchen? Soll ich es aus dem Routing-Schema entfernen? Und was bedeutet „zu langsam“ – wie viele sind es in Zahlen und wer bestimmt sie? Vielleicht einfach eine Pause einlegen und es später noch einmal versuchen? Wenn ja, wie viel später?
Was ist Pool-Auswurf in Istio?
Und hier kommt Istio mit seinen Circuit Breaker-Schutzmaschinen zur Rettung, die fehlerhafte Container vorübergehend aus dem Routing- und Load-Balancing-Ressourcenpool entfernen und dabei das Pool-Ejection-Verfahren implementieren.
Mithilfe einer Ausreißererkennungsstrategie erkennt Istio Kurven-Pods, die außerhalb der Linie liegen, und entfernt sie für einen bestimmten Zeitraum, der als Ruhefenster bezeichnet wird, aus dem Ressourcenpool.
Um zu zeigen, wie das in Kubernetes auf der OpenShift-Plattform funktioniert, beginnen wir mit einem Screenshot normal funktionierender Microservices aus dem Beispiel im Repository
Bereiten Sie sich auf einen Absturz vor
Bevor Sie den Pool-Auswurf durchführen, müssen Sie eine Istio-Routing-Regel erstellen. Nehmen wir an, wir möchten Anfragen im Verhältnis 50/50 auf die Pods verteilen. Darüber hinaus werden wir die Anzahl der v2-Container von eins auf zwei erhöhen, wie folgt:
oc scale deployment recommendation-v2 --replicas=2 -n tutorial
Jetzt legen wir eine Routing-Regel fest, sodass der Datenverkehr im Verhältnis 50/50 auf die Pods verteilt wird.
So sieht das Ergebnis dieser Regel aus:
Man kann es bemängeln, dass dieser Bildschirm nicht 50/50, sondern 14:9 ist, aber mit der Zeit wird sich die Situation verbessern.
Einen Fehler machen
Jetzt deaktivieren wir einen der beiden v2-Container, sodass wir einen fehlerfreien v1-Container, einen fehlerfreien v2-Container und einen fehlerhaften v2-Container haben:
Den Fehler beheben
Wir haben also einen fehlerhaften Container und es ist Zeit für den Pool-Auswurf. Mithilfe einer sehr einfachen Konfiguration schließen wir diesen ausgefallenen Container für 15 Sekunden von allen Routing-Schemata aus, in der Hoffnung, dass er in einen fehlerfreien Zustand zurückkehrt (entweder Neustart oder Wiederherstellung der Leistung). So sieht diese Konfiguration aus und die Ergebnisse ihrer Arbeit:
Wie Sie sehen, wird der ausgefallene v2-Container nicht mehr für Routing-Anfragen verwendet, da er aus dem Pool entfernt wurde. Aber nach 15 Sekunden kehrt es automatisch in den Pool zurück. Eigentlich haben wir gerade gezeigt, wie Pool Ejection funktioniert.
Beginnen wir mit dem Bau von Architektur
Mit Pool Ejection können Sie in Kombination mit den Überwachungsfunktionen von Istio mit dem Aufbau eines Frameworks für den automatischen Austausch fehlerhafter Container beginnen, um Ausfallzeiten und Ausfälle zu reduzieren, wenn nicht sogar ganz zu vermeiden.
Die NASA hat ein lautes Motto – Scheitern ist keine Option, dessen Autor als Flugdirektor gilt
Istio implementiert, wie wir oben geschrieben haben, das Konzept der Leistungsschalter, das sich in der physischen Welt bestens bewährt hat. Und genau wie ein elektrischer Schutzschalter einen problematischen Abschnitt eines Stromkreises abschaltet, öffnet Istios Software Circuit Breaker die Verbindung zwischen einem Anforderungsstrom und einem Problemcontainer, wenn mit dem Endpunkt etwas nicht stimmt, beispielsweise wenn der Server abgestürzt ist oder zu funktionieren begann verlangsamen.
Darüber hinaus gibt es im zweiten Fall nur noch mehr Probleme, da die Bremsen eines Containers nicht nur zu einer Kaskade von Verzögerungen bei den darauf zugreifenden Diensten führen und dadurch die Leistung des Gesamtsystems verringern, sondern auch zu wiederholten Verzögerungen führen Anfragen an einen bereits langsam laufenden Dienst, was die Situation nur verschlimmert.
Leistungsschalter in der Theorie
Circuit Breaker ist ein Proxy, der den Fluss von Anfragen an einen Endpunkt steuert. Wenn dieser Punkt nicht mehr funktioniert oder, abhängig von den angegebenen Einstellungen, langsamer wird, unterbricht der Proxy die Verbindung mit dem Container. Der Datenverkehr wird dann einfach aufgrund des Lastausgleichs auf andere Container umgeleitet. Die Verbindung bleibt für ein bestimmtes Schlaffenster, beispielsweise zwei Minuten, geöffnet und gilt dann als halboffen. Ein Versuch, die nächste Anfrage zu senden, bestimmt den weiteren Zustand der Verbindung. Wenn mit dem Dienst alles in Ordnung ist, kehrt die Verbindung in den Betriebszustand zurück und wird wieder geschlossen. Wenn immer noch etwas mit dem Dienst nicht stimmt, wird die Verbindung getrennt und das Ruhefenster wird wieder aktiviert. So sieht ein vereinfachtes Leistungsschalter-Zustandsdiagramm aus:
Dabei ist zu beachten, dass dies alles sozusagen auf der Ebene der Systemarchitektur geschieht. Irgendwann müssen Sie Ihren Anwendungen also beibringen, mit Circuit Breaker zu arbeiten, indem Sie beispielsweise einen Standardwert als Antwort bereitstellen oder, wenn möglich, die Existenz des Dienstes ignorieren. Hierzu wird ein Schottmuster verwendet, das jedoch den Rahmen dieses Artikels sprengen würde.
Leistungsschalter in der Praxis
Beispielsweise werden wir zwei Versionen unseres Empfehlungs-Microservices auf OpenShift ausführen. Version 1 wird gut funktionieren, aber in Version 2 werden wir eine Verzögerung einbauen, um Verlangsamungen auf dem Server zu simulieren. Um die Ergebnisse anzuzeigen, verwenden Sie das Tool
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 100-prozentige Verfügbarkeit, aber schauen Sie genauer hin – die maximale Transaktionsdauer beträgt sogar 12 Sekunden. Dies stellt eindeutig einen Engpass dar und muss ausgebaut werden.
Dazu verwenden wir Istio, um Aufrufe an langsame Container zu eliminieren. So sieht die entsprechende Konfiguration mit Circuit Breaker aus:
Die letzte Zeile mit dem Parameter httpMaxRequestsPerConnection signalisiert, dass die Verbindung mit getrennt werden soll, wenn versucht wird, zusätzlich zur bestehenden eine weitere – eine zweite – Verbindung herzustellen. Da unser Container einen langsamen Dienst simuliert, treten solche Situationen regelmäßig auf, und Istio gibt dann einen 503-Fehler zurück, aber Folgendes wird bei Siege angezeigt:
OK, wir haben den Leistungsschalter, was kommt als nächstes?
Deshalb haben wir das automatische Herunterfahren implementiert, ohne den Quellcode der Dienste selbst zu berühren. Mithilfe von Circuit Breaker und dem oben beschriebenen Pool-Auswurfverfahren können wir Bremscontainer aus dem Ressourcenpool entfernen, bis sie wieder normal sind, und ihren Status in einer bestimmten Häufigkeit überprüfen – in unserem Beispiel sind dies zwei Minuten (sleepWindow-Parameter).
Beachten Sie, dass die Fähigkeit einer Anwendung, auf einen 503-Fehler zu reagieren, immer noch auf der Quellcodeebene festgelegt wird. Je nach Situation gibt es viele Strategien für den Einsatz von Leistungsschaltern.
Im nächsten Beitrag: Wir sprechen über die Ablaufverfolgung und Überwachung, die bereits integriert ist oder einfach in Istio hinzugefügt werden kann, und darüber, wie man absichtlich Fehler in das System einschleusen kann.
Source: habr.com