Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.
Leistungsschaltermuster
Absicht
Das Leistungsschaltermuster kann verhindern, dass ein Aufruferservice einen Aufruf an einen anderen Service (Anrufempfänger) wiederholt, wenn der Aufruf zuvor wiederholte Timeouts oder Fehler verursacht hat. Das Muster wird auch verwendet, um zu erkennen, wann der Anruferservice wieder funktioniert.
Motivation
Wenn mehrere Microservices zusammenarbeiten, um Anfragen zu bearbeiten, können ein oder mehrere Services nicht verfügbar sein oder eine hohe Latenz aufweisen. Wenn komplexe Anwendungen Microservices verwenden, kann ein Ausfall in einem Microservice zu Anwendungsausfällen führen. Microservices kommunizieren über Remote-Prozeduraufrufe, und es können vorübergehende Fehler in der Netzwerkkonnektivität auftreten, die zu Fehlern führen. (Die vorübergehenden Fehler können mithilfe des Wiederholungsversuchs mit Backoff-Muster behandelt werden.) Während der synchronen Ausführung kann die Kaskadierung von Timeouts oder Fehlern zu einer schlechten Benutzererfahrung führen.
In einigen Situationen können die Fehler jedoch länger dauern, z. B. wenn der Aufruferservice ausgefallen ist oder ein Datenbankkonflikt zu Timeouts führt. Wenn der aufrufende Service die Aufrufe wiederholt wiederholt wiederholt, können diese Wiederholungen zu Netzwerkkonflikten und der Nutzung des Datenbank-Threadpools führen. Wenn mehrere Benutzer die Anwendung wiederholt wiederholen, verschlimmert dies das Problem und kann zu Leistungseinbußen in der gesamten Anwendung führen.
Das Leistungsschaltermuster wurde von Bol Nygard in seinem Buch Release It (Nygard 2018) verbreitet. Dieses Designmuster kann verhindern, dass ein Anruferservice einen Serviceaufruf wiederholt, der zuvor wiederholte Timeouts oder Fehler verursacht hat. Es kann auch erkennen, wann der Anruferservice wieder funktioniert.
Schutzschalterobjekte funktionieren wie Schutzschalter, die den Strom automatisch unterbrechen, wenn eine Anomalie in der Verbindung vorliegt. Schutzschalter schalten den Fluss des Stroms ab oder schalten ihn aus, wenn ein Fehler auftritt. In ähnlicher Weise befindet sich das Schutzschalterobjekt zwischen dem Aufrufer und dem Aufruferdienst und wird ausgelöst, wenn der Aufrufer nicht verfügbar ist.
Die Fallzeiten verteilter Datenverarbeitung
Während eines Netzwerkausfalls warten Anwendungen möglicherweise auf unbestimmte Zeit auf eine Antwort und verbrauchen kontinuierlich Anwendungsressourcen. Wenn die Operationen nicht wiederholt werden, wenn das Netzwerk verfügbar ist, kann dies auch zu einer Beeinträchtigung der Anwendung führen. Wenn API-Aufrufe an eine Datenbank oder einen externen Service aufgrund von Netzwerkproblemen ausfallen, können sich wiederholte Aufrufe ohne Leistungsschalter auf Kosten und Leistung auswirken.
Anwendbarkeit
Verwenden Sie dieses Muster, wenn:
-
Der Anruferservice führt einen Aufruf durch, der höchstwahrscheinlich fehlschlägt.
-
Eine hohe Latenz, die der Aufruferservice zeigt (z. B. wenn Datenbankverbindungen langsam sind), führt zu Timeouts für den Aufruferservice.
-
Der Anruferservice führt einen synchronen Aufruf durch, aber der Anruferservice ist nicht verfügbar oder weist eine hohe Latenz auf.
Fehler und Überlegungen
-
Serviceunabhängige Implementierung: Um eine Überlastung des Codes zu verhindern, empfehlen wir Ihnen, das Schutzschalterobjekt auf Microservice-unabhängige und API-gesteuerte Weise zu implementieren.
-
Schließen des Kreises durch den Aufrufer: Wenn der Aufrufer nach dem Leistungsproblem oder -fehler wiederhergestellt ist, kann er den Verbindungsstatus auf aktualisieren
CLOSED
. Dies ist eine Erweiterung des Leistungsschaltermusters und kann implementiert werden, wenn Ihr Recovery Time Objective (RTO) dies erfordert. -
Multithread-Aufrufe: Der Ablauf-Timeout-Wert ist definiert als der Zeitraum, in dem die Verbindung ausgelöst wird, bevor Aufrufe erneut weitergeleitet werden, um die Serviceverfügbarkeit zu überprüfen. Wenn der Aufrufer-Service in mehreren Threads aufgerufen wird, definiert der erste fehlgeschlagene Aufruf den Ablauf-Timeout-Wert. Ihre Implementierung sollte sicherstellen, dass nachfolgende Aufrufe das Ablauf-Timeout nicht unbegrenzt verschieben.
-
Öffnen oder Schließen der Verbindung erzwingen: Systemadministratoren sollten eine Verbindung öffnen oder schließen können. Dazu aktualisieren Sie den Ablauf-Timeout-Wert in der Datenbanktabelle.
-
Beobachtbarkeit: Für die Anwendung sollte die Protokollierung eingerichtet sein, um die Aufrufe zu identifizieren, die fehlschlagen, wenn der Schutzschalter geöffnet ist.
Implementierung
Hochrangige Architektur
Im folgenden Beispiel ist der Aufrufer der Bestellservice und der Aufrufer der Zahlungsservice.
Wenn es keine Fehler gibt, leitet der Bestellservice alle Aufrufe über den Leistungsschalter an den Zahlungsservice weiter, wie das folgende Diagramm zeigt.
![Schutzschaltermuster ohne Fehler.](images/circuit-breaker-1.png)
Wenn der Zahlungsservice eine Zeitüberschreitung aufweist, kann der Leistungsschalter die Zeitüberschreitung erkennen und den Fehler verfolgen.
![Schutzschalter mit Zahlungsdienstausfall.](images/circuit-breaker-2.png)
Wenn die Timeouts einen bestimmten Schwellenwert überschreiten, öffnet die Anwendung die -schaltung. Wenn die Verbindung geöffnet ist, leitet das Leistungsschalterobjekt die Aufrufe nicht an den Zahlungsservice weiter. Sie gibt einen sofortigen Fehler zurück, wenn der Bestellservice den Zahlungsservice aufruft.
![Der Schutzschalter stoppt das Routing an den Zahlungsservice.](images/circuit-breaker-3.png)
Das Leistungsschalterobjekt versucht regelmäßig zu sehen, ob die Aufrufe des Zahlungsservices erfolgreich sind.
![Der Schutzschalter wiederholt den Zahlungsservice regelmäßig.](images/circuit-breaker-4.png)
Wenn der Aufruf an den Zahlungsservice erfolgreich ist, wird die Verbindung geschlossen und alle weiteren Aufrufe werden erneut an den Zahlungsservice weitergeleitet.
![Schutzschalter mit funktionierendem Zahlungsservice.](images/circuit-breaker-5.png)
Implementierung mithilfe von AWS-Services
Die Beispiellösung verwendet Express-Workflows in AWS Step Functions
Die Lösung verwendet auch eine Amazon-DynamoDB
Wenn ein Service einen anderen Service aufrufen möchte, startet er den Workflow mit dem Namen des Aufruferservices. Der Workflow ruft den Leistungsschalterstatus aus der DynamoDB-CircuitStatus
Tabelle ab, in der die aktuell beeinträchtigten Services gespeichert sind. Wenn einen nicht abgelaufenen Datensatz für den Aufrufer CircuitStatus
enthält, ist die Verbindung geöffnet. Der Step Functions-Workflow gibt einen sofortigen Fehler zurück und wird mit dem FAIL
Status beendet.
Wenn die CircuitStatus
Tabelle keinen Datensatz für den Aufrufer oder einen abgelaufenen Datensatz enthält, ist der Service betriebsbereit. Der ExecuteLambda
Schritt in der Definition des Zustandsautomaten ruft die Lambda-Funktion auf, die über einen Parameterwert gesendet wird. Wenn der Aufruf erfolgreich ist, wird der Step-Functions-Workflow mit dem SUCCESS
Status beendet.
![Implementierung des Schutzschalters mit AWS Step Functions und DynamoDB .](images/circuit-breaker-6.png)
Wenn der Serviceaufruf fehlschlägt oder ein Timeout auftritt, wiederholt die Anwendung den Vorgang mit exponentiellem Backoff für eine bestimmte Anzahl von Malen. Wenn der Serviceaufruf nach dem erneuten Versuch fehlschlägt, fügt der Workflow einen Datensatz in die CircuitStatus
Tabelle für den Service mit einem ein ExpiryTimeStamp
und der Workflow wird mit einem -FAIL
Status beendet. Nachfolgende Aufrufe desselben Services geben einen sofortigen Fehler zurück, solange der Leistungsschalter geöffnet ist. Der Get Circuit Status
Schritt in der Definition des Zustandsautomaten überprüft die Serviceverfügbarkeit basierend auf dem ExpiryTimeStamp
Wert . Abgelaufene Elemente werden mithilfe der DynamoDB-TTL-Funktion (Time to Live) aus der CircuitStatus
Tabelle gelöscht.
Beispiel-Code
Der folgende Code verwendet die GetCircuitStatus
Lambda-Funktion, um den Status des Leistungsschalters zu überprüfen.
var serviceDetails = _dbContext.QueryAsync<CircuitBreaker>(serviceName, QueryOperator.GreaterThan, new List<object> {currentTimeStamp}).GetRemainingAsync(); if (serviceDetails.Result.Count > 0) { functionData.CircuitStatus = serviceDetails.Result[0].CircuitStatus; } else { functionData.CircuitStatus = ""; }
Der folgende Code zeigt die Amazon States Language-Anweisungen im Step Functions-Workflow.
"Is Circuit Closed": { "Type": "Choice", "Choices": [ { "Variable": "$.CircuitStatus", "StringEquals": "OPEN", "Next": "Circuit Open" }, { "Variable": "$.CircuitStatus", "StringEquals": "", "Next": "Execute Lambda" } ] }, "Circuit Open": { "Type": "Fail" }
GitHub -Repository
Eine vollständige Implementierung der Beispielarchitektur für dieses Muster finden Sie im GitHub Repository unter https://github.com/aws-samples/circuit-breaker-netcore-blog