Bearbeiten

Freigeben über


Trennschalter-Muster

Azure

Behandeln Sie Fehler, deren Behebung beim Herstellen einer Verbindung mit einem Remotedienst oder einer Remoteressource unterschiedlich lange dauern kann. Dieses Muster kann die Stabilität und Resilienz einer Anwendung verbessern.

Kontext und Problem

In einer verteilten Umgebung können Anrufe an Remoteressourcen und -dienste aufgrund vorübergehender Fehler fehlschlagen, z. B. langsame Netzwerkverbindungen, Timeouts oder die Ressourcen, die überlastet oder vorübergehend nicht verfügbar sind. Diese Störungen korrigieren sich typischerweise nach kurzer Zeit selbst, und eine robuste Cloudanwendung sollte bereit sein, sie mit einer Strategie wie dem Wiederholungsmuster zu behandeln.

Es kann aber auch Situationen geben, in denen Störungen bzw. Fehler auf unvorhergesehene Ereignisse zurückzuführen sind, deren Behebung viel länger dauern kann. Zu unterscheiden sind unterschiedliche Schweregrade, die von einem Teilverlust der Konnektivität bis hin zum vollständigen Ausfall des Diensts reichen können. In diesen Situationen kann es sinnlos sein, dass eine Anwendung einen Vorgang, der nicht erfolgreich ist, kontinuierlich wiederholen kann, und stattdessen sollte die Anwendung schnell akzeptieren, dass der Vorgang fehlgeschlagen ist und diesen Fehler entsprechend behandelt.

Wenn ein Dienst zudem sehr ausgelastet ist, kann ein Ausfall in einem Teil des Systems zu überlappenden Fehlern führen. Beispielsweise könnte ein Vorgang, der einen Dienst aufruft, so konfiguriert werden, dass ein Timeout implementiert wird, und mit einer Fehlermeldung antworten, wenn der Dienst innerhalb dieses Zeitraums nicht reagiert. Diese Strategie könnte jedoch dazu führen, dass viele gleichzeitige Anforderungen an denselben Vorgang blockiert werden, bis der Timeoutzeitraum abläuft. Diese blockierten Anforderungen können kritische Systemressourcen belegen, z. B. Arbeitsspeicher, Threads, Datenbankverbindungen usw. Daher könnten diese Ressourcen erschöpft werden, was zu einem Ausfall anderer möglicherweise nicht zusammenhängender Teile des Systems führt, die dieselben Ressourcen verwenden müssen. In solchen Situationen wäre es vorzuziehen, wenn der Vorgang sofort einen Fehler aufweist und nur dann versucht wird, den Dienst aufzurufen, wenn er voraussichtlich erfolgreich sein wird. Das Festlegen eines kürzeren Timeouts kann dazu beitragen, dieses Problem zu beheben, aber das Timeout sollte nicht so kurz sein, dass der Vorgang die meiste Zeit fehlschlägt, auch wenn die Anforderung an den Dienst letztendlich erfolgreich war.

Lösung

Das Schaltkreisbrechermuster kann verhindern, dass eine Anwendung wiederholt versucht, einen Vorgang auszuführen, der wahrscheinlich fehlschlägt. Dabei wird die Fortsetzung des Vorgangs gestattet, ohne auf eine Behebung der Störung zu warten oder CPU-Zyklen zu verschwenden, während ermittelt wird, dass es sich um einen länger anhaltenden Fehler handelt. Mithilfe des Trennschalter-Musters kann eine Anwendung auch ermitteln, ob der Fehler behoben wurde. Wenn das Problem scheinbar behoben ist, kann die Anwendung versuchen, den Vorgang aufzurufen.

Der Zweck des Trennschalter-Musters unterscheidet sich von dem des Wiederholungsmusters. Mithilfe des Wiederholungsmusters kann eine Anwendung einen Vorgang in der Annahme wiederholen, dass er erfolgreich ausgeführt wird. Das Trennschalter-Muster verhindert, dass von einer Anwendung ein Vorgang durchgeführt wird, der voraussichtlich nicht erfolgreich sein wird. Eine Anwendung kann diese beiden Muster kombinieren, indem sie das Wiederholungsmuster verwendet, um einen Vorgang über einen Trennschalter aufzurufen. Die Wiederholungslogik sollte jedoch auf Ausnahmen reagieren, die vom Trennschalter zurückgegeben werden, und Wiederholungsversuche abbrechen, wenn der Trennschalter anzeigt, dass ein Fehler nicht vorübergehend ist.

Ein Trennschalter fungiert als Proxy für Vorgänge, bei denen möglicherweise Fehler auftreten. Der Proxy sollte die Anzahl der zuletzt aufgetretenen Fehler überwachen und anhand dieser Informationen entscheiden, ob der Vorgang fortgesetzt oder sofort eine Ausnahme zurückgegeben werden soll.

Der Proxy kann als Zustandsautomat mit den folgenden Zuständen implementiert werden, die die Funktionalität eines elektrischen Trennschalters simulieren:

  • Geschlossen: Die Anforderung der Anwendung wird an den Vorgang weitergeleitet. Der Proxy führt eine Zählung der Anzahl der letzten Fehler durch, und wenn der Aufruf des Vorgangs erfolglos ist, inkrementiert der Proxy diesen Zähler. Überschreitet die Anzahl der letzten Fehler innerhalb eines bestimmten Zeitraums einen bestimmten Schwellenwert, wird der Proxy in den Zustand Geöffnet versetzt. An diesem Punkt startet der Proxy einen Timeouttimer, und wenn dieser Timer abläuft, wird der Proxy in den Halböffent- Zustand versetzt.

    Der Zweck des Timeouttimers besteht darin, dem System Zeit zu geben, um das Problem zu beheben, das den Fehler verursacht hat, bevor die Anwendung versuchen kann, den Vorgang erneut auszuführen.

  • Geöffnet: Die Anforderung der Anwendung schlägt sofort fehl und eine Ausnahme wird an die Anwendung zurückgegeben.

  • Halb geöffnet: Eine begrenzte Anzahl von Anforderungen aus der Anwendung dürfen den Vorgang durchlaufen und aufrufen. Wenn diese Anforderungen erfolgreich sind, wird davon ausgegangen, dass die Störung, die zuvor den Fehler verursacht hat, behoben wurde und der Trennschalter in den Zustand Geschlossen wechselt (der Fehlerzähler wird zurückgesetzt). Wenn eine Anforderung fehlschlägt, geht der Schaltkreisumbruch davon aus, dass der Fehler weiterhin vorhanden ist, sodass er auf den Open Zustand zurückgesetzt wird und den Timeouttimer neu startet, um dem System einen weiteren Zeitraum zur Wiederherstellung des Fehlers zu geben.

    Mit dem Zustand Halb geöffnet kann verhindert werden, dass ein in der Wiederherstellung befindlicher Dienst plötzlich mit Anforderungen überschwemmt wird. Wenn ein Dienst wiederhergestellt wird, kann er möglicherweise eine begrenzte Anzahl von Anforderungen unterstützen, bis die Wiederherstellung abgeschlossen ist. Aber während der Wiederherstellung kann eine Vielzahl an Aufgaben dazu führen, dass der Dienst erneut den Timeout überschreitet oder ausfällt.

Trennschalterzustände

In der Abbildung ist der vom Zustand Geschlossen verwendete Fehlerzähler zeitbasiert. Er wird in regelmäßigen Abständen automatisch zurückgesetzt. Dieses Design trägt dazu bei, zu verhindern, dass der Schaltkreisschalter in den Open Zustand wechselt, wenn gelegentlich Fehler auftreten. Der Fehlerschwellenwert, der den Trennschalter in den Zustand Geöffnet versetzt, wird nur erreicht, wenn innerhalb eines bestimmten Intervalls eine bestimmte Anzahl von Fehlern aufgetreten ist. Der Zähler, der vom Zustand Halb geöffnet verwendet wird, zeichnet die Anzahl der erfolgreichen Versuche beim Aufrufen des Vorgangs auf. Der Trennschalter kehrt in den Zustand Geschlossen zurück, nachdem eine bestimmte Anzahl aufeinanderfolgender Vorgangsaufrufe erfolgreich durchgeführt wurde. Wenn bei einem Aufruf ein Fehler auftritt, wechselt der Trennschalter sofort in den Zustand Geöffnet und der Erfolgszähler wird zurückgesetzt, wenn er das nächste Mal in den Zustand Halb geöffnet wechselt.

Die Wiederherstellung des Systems erfolgt extern, möglicherweise durch Wiederherstellen oder Neustarten einer fehlerhaften Komponente oder durch Reparieren einer Netzwerkverbindung.

Das Trennschalter-Muster sorgt für Stabilität, während sich das System nach einem Fehler erholt und die Auswirkungen auf die Leistung minimiert. Es kann dabei helfen, die Antwortzeit des Systems zu wahren, indem es eine Anforderung für einen Vorgang, der voraussichtlich nicht erfolgreich sein wird, schnell ablehnt, anstatt darauf zu warten, dass der Vorgang abgebrochen wird oder niemals zurückkehrt. Wenn der Trennschalter bei jeder Zustandsänderung ein Ereignis auslöst, kann diese Information dazu verwendet werden, den Zustand des durch den Trennschalter geschützten Teils des Systems zu überwachen oder einen Administrator zu alarmieren, wenn ein Trennschalter in den Zustand Geöffnet wechselt.

Das Muster ist anpassbar und kann je nach Art des möglichen Fehlers geändert werden. Sie können z. B. einen zunehmenden Timeouttimer auf einen Schaltkreisschalter anwenden. Sie können den Schaltkreistrennschalter zunächst im Zustand "öffnen" "Öffnen" für einige Sekunden platzieren, und wenn der Fehler nicht behoben wurde, erhöhen Sie das Timeout auf ein paar Minuten usw.. In manchen Fällen kann es sinnvoll sein, anstelle des Zustandes Geöffnet, der einen Fehler zurückgibt und eine Ausnahme auslöst, einen Standardwert zurückzugeben, der für die Anwendung relevant ist.

Hinweis

Traditionell basieren Schaltkreisbrecher auf vorkonfigurierte Schwellenwerte wie Fehleranzahl und Timeoutdauer, was zu einem deterministischen, aber manchmal suboptimalen Verhalten führt. Adaptive Techniken, die KI und ML verwenden, können jedoch Schwellenwerte basierend auf Echtzeitdatenverkehrsmustern, Anomalien und historischen Fehlerraten dynamisch anpassen, wodurch der Schaltkreisbrecher stabiler und effizienter wird.

Probleme und Überlegungen

Bei der Entscheidung, wie dieses Muster implementiert werden soll, sind die folgenden Punkte zu beachten:

Ausnahmebehandlung: Eine Anwendung, die einen Vorgang über einen Schaltkreisschalter aufruft, muss vorbereitet sein, um die ausgelösten Ausnahmen zu behandeln, wenn der Vorgang nicht verfügbar ist. Die Art und Weise, wie Ausnahmen behandelt werden, ist anwendungsspezifisch. Eine Anwendung könnte z. B. vorübergehend ihre Funktionalität herabsetzen, einen alternativen Vorgang aufrufen, um zu versuchen, dieselbe Aufgabe auszuführen oder dieselben Daten zu erhalten, oder die Ausnahme dem Benutzer melden und ihn auffordern, es später erneut zu versuchen.

Typen von Ausnahmen: Eine Anforderung kann aus vielen Gründen fehlschlagen, von denen einige auf einen schwerwiegenderen Fehlertyp hinweisen können als andere. Eine Anforderung kann z. B. fehlschlagen, weil ein Remotedienst abgestürzt ist und mehrere Minuten dauert, um wiederherzustellen, oder aufgrund eines Timeouts, weil der Dienst vorübergehend überlastet wird. Ein Trennschalter könnte in der Lage sein, die Art der aufgetretenen Ausnahmen zu untersuchen und seine Strategie entsprechend der Art dieser Ausnahmen anzupassen. Es kann z. B. eine größere Anzahl von Timeoutausnahmen erfordern, um den Schaltkreistrennschalter in den Zustand Open im Vergleich zur Anzahl der Fehler aufgrund der vollständigen Nichtverfügbarkeit des Diensts zu durchlaufen.

Überwachung: Ein Schaltkreisschalter sollte sowohl fehlerhafte als auch erfolgreiche Anforderungen klar beobachten, sodass Betriebsteams die Systemintegrität bewerten können. Verwenden Sie die verteilte Ablaufverfolgung für die End-to-End-Sichtbarkeit über Dienste hinweg.

Wiederherstellbarkeit: Sie sollten den Schaltkreistrennschalter so konfigurieren, dass es dem wahrscheinlichen Wiederherstellungsmuster des zu schützenden Vorgangs entspricht. Wenn sich der Trennschalter z. B. über einen längeren Zeitraum im Zustand Geöffnet befindet, kann er Ausnahmen auslösen, auch wenn die Fehlerursache behoben ist. Ebenso könnte ein Trennschalter schwanken und die Reaktionszeiten von Anwendungen verkürzen, wenn er zu schnell vom Zustand Geöffnet in den Zustand Halb geöffnet wechselt.

Testen fehlgeschlagener Vorgänge: Im Zustand Öffnen statt einen Timer zu verwenden, um zu bestimmen, wann der Halböffentlich- Zustand gewechselt werden soll, kann ein Schaltschalter stattdessen regelmäßig den Remotedienst oder die Ressource pingen, um zu bestimmen, ob er wieder verfügbar wird. Dieser Ping-Befehl könnte die Form eines Aufrufversuchs für einen Vorgang annehmen, der zuvor fehlerhaft war, oder er könnte einen speziellen Vorgang verwenden, der vom Remotedienst speziell für die Prüfung der Integrität des Dienstes bereitgestellt wird, wie durch das Muster zur Überwachung des Integritätsendpunkts beschrieben.

manuelle Außerkraftsetzung: In einem System, in dem die Wiederherstellungszeit für einen fehlerhaften Vorgang extrem variabel ist, ist es vorteilhaft, eine manuelle Rücksetzungsoption bereitzustellen, mit der ein Administrator einen Schaltkreistrennschalter schließen kann (und den Fehlerzähler zurücksetzen kann). Ebenso könnte ein Administrator einen Schaltkreistrennschalter in den Zustand Öffnen erzwingen (und den Timeouttimer neu starten), wenn der durch den Schaltschalter geschützte Vorgang vorübergehend nicht verfügbar ist.

Parallelität: Auf denselben Schaltkreistrennschalter kann durch eine große Anzahl gleichzeitiger Instanzen einer Anwendung zugegriffen werden. Die Implementierung sollte keine gleichzeitigen Anforderungen blockieren oder übermäßigen Aufwand für die einzelnen Aufrufe eines Vorgangs verursachen.

Ressourcendifferenzierung: Achten Sie beim Verwenden eines einzelnen Schaltkreisschalters für einen Ressourcentyp, wenn mehrere zugrunde liegende unabhängige Anbieter vorhanden sein könnten. In einem Datenspeicher, der mehrere Shards enthält, kann z. B. auf einen Shard uneingeschränkt zugegriffen werden, während bei einem anderen Shard ein temporäres Problem auftritt. Wenn die Fehlerreaktionen in diesen Szenarien zusammengeführt werden, könnte eine Anwendung versuchen, auf einige Shards zuzugreifen, selbst wenn ein Fehler sehr wahrscheinlich ist, während der Zugriff auf andere Shards blockiert wird, obwohl er voraussichtlich erfolgreich sein wird.

Beschleunigter Schaltkreisbruch: Manchmal kann eine Fehlerantwort genügend Informationen für den Schaltkreisschalter enthalten, um sofort zu fahren und für eine minimale Zeit zu bleiben. Die Fehlerreaktion einer freigegebenen Ressource, die überlastet ist, könnte z. B. darauf hinweisen, dass eine sofortige Wiederholung nicht empfohlen wird. Stattdessen sollte es die Anwendung in einigen Minuten erneut versuchen.

Bereitstellungen mit mehreren Regionen: Ein Schaltkreisschalter kann für Bereitstellungen mit einer oder mehreren Regionen entwickelt werden. Letzteres kann mit globalen Lastenausgleichsmodulen oder benutzerdefinierten, regionenfähigen Schaltkreisbrechungsstrategien implementiert werden, die eine kontrollierte Failover-, Latenzoptimierung und behördliche Compliance gewährleisten.

Dienstgitterschalter: Schaltschalter können auf der Anwendungsschicht oder als quergeschnittene, abstrahierte Funktion implementiert werden. Beispielsweise unterstützen Dienstgitter häufig Schaltkreisbrüche als Sidecar- oder als eigenständige Funktion, ohne den Anwendungscode zu ändern.

Hinweis

Ein Dienst kann HTTP 429 (Zu viele Anforderungen) zurückgeben, wenn er den Client einschränkt, oder HTTP 503 (Dienst nicht verfügbar), wenn der Dienst derzeit nicht verfügbar ist. Die Antwort kann zusätzliche Informationen enthalten, z. B. die erwartete Dauer der Verzögerung.

Fehler bei der Wiedergabe fehlgeschlagener Anforderungen: Im Zustand "Öffnen" könnte ein Schaltkreisumbruch auch die Details jeder Anforderung an ein Journal aufzeichnen und festlegen, dass diese Anforderungen wiedergegeben werden, wenn die Remoteressource oder der Remotedienst verfügbar ist.

Unangemessene Timeouts für externe Dienste: Ein Schaltkreisschalter kann Anwendungen möglicherweise nicht vollständig vor Vorgängen schützen, die in externen Diensten fehlschlagen, die mit einem langen Timeoutzeitraum konfiguriert sind. Wenn das Timeout zu lang ist, kann ein Thread, der einen Schaltkreisschalter ausführt, für einen längeren Zeitraum blockiert werden, bevor der Schaltkreisschalter angibt, dass der Vorgang fehlgeschlagen ist. In dieser Zeit könnten viele andere Anwendungsinstanzen ebenfalls versuchen, den Dienst über den Trennschalter aufzurufen und eine beträchtliche Anzahl von Threads zu binden, bevor sie alle ausfallen.

Anpassungsfähigkeit an die Berechnungsdiversifizierung: Schaltkreisbrecher sollten unterschiedliche Computeumgebungen berücksichtigen, von serverlosen bis zu containerisierten Workloads, bei denen Faktoren wie Kaltstarts und Skalierbarkeit die Fehlerbehandlung beeinträchtigen. Adaptive Ansätze können Strategien basierend auf dem Computetyp dynamisch anpassen und dabei die Resilienz über heterogene Architekturen hinweg sicherstellen.

Verwendung dieses Musters

Verwenden Sie dieses Muster in folgenden Fällen:

  • Um Kaskadierende Fehler zu verhindern, indem übermäßige Aufrufe durch einen Remotedienst oder Zugriffsanforderungen an eine freigegebene Ressource beendet werden, wenn diese Vorgänge höchstwahrscheinlich fehlschlagen.
  • Zur Verbesserung der Resilienz in mehreren Regionen durch intelligentes Routing des Datenverkehrs basierend auf Echtzeitfehlersignalen.
  • Um sich vor langsamen Abhängigkeiten zu schützen, helfen Sie dabei, ihre Ziele auf Dienstebene (SLOs) einzuhalten und leistungseinbußen aufgrund von Diensten mit hoher Latenz zu vermeiden.
  • Um zeitweilige Konnektivitätsprobleme zu behandeln und Anforderungsfehler in verteilten Umgebungen zu reduzieren.

Verwenden Sie dieses Muster in folgenden Fällen nicht:

  • Für die Verwaltung des Zugriffs auf lokale private Ressourcen in einer Anwendung, z. B. die In-Memory-Datenstruktur. In dieser Umgebung würde die Verwendung eines Trennschalters zu einem zusätzlichen Aufwand für Ihr System führen.
  • Als Ersatz für die Behandlung von Ausnahmen in der Geschäftslogik Ihrer Anwendungen.
  • Wenn bekannte Wiederholungsalgorithmen ausreichend sind und Ihre Abhängigkeiten für die Behandlung von Wiederholungsmechanismen konzipiert sind. Die Implementierung eines Schaltkreisschalters in Ihrer Anwendung in diesem Fall könnte Ihrem System unnötige Komplexität verleihen.
  • Wenn auf das Zurücksetzen eines Schaltkreisschalters gewartet wird, kann es zu inakzeptablen Verzögerungen kommen.
  • Wenn Sie über eine nachrichtengesteuerte oder ereignisgesteuerte Architektur verfügen, da sie häufig fehlgeschlagene Nachrichten für die manuelle oder verzögerte Verarbeitung an eine Warteschlange für inaktive Briefe (Dead Letter Queue, DLQ) weiterleiten. Die integrierte Fehlerisolation und Wiederholungsmechanismen, die in diesen Designs üblicherweise implementiert sind, reichen häufig aus.
  • Wenn die Wiederherstellung von Fehlern auf Infrastruktur- oder Plattformebene verwaltet wird, z. B. bei Integritätsprüfungen in globalen Lastenausgleichsmodulen oder Dienstgittern, sind schaltkreisbrecher möglicherweise nicht erforderlich.

Workloadentwurf

Ein Architekt sollte evaluieren, wie das Circuit Breaker-Muster im Design seiner Workloads verwendet werden kann, um die Ziele und Prinzipien zu erreichen, die in den Azure Well-Architected Framework-Säulen behandelt werden. Zum Beispiel:

Säule So unterstützt dieses Muster die Säulenziele
Zuverlässigkeitsdesignentscheidungen tragen dazu bei, dass Ihre Workload ausfallsicher wird und dass sie nach einem Ausfall wieder in einen voll funktionsfähigen Zustand zurückkehrt. Dieses Muster verhindert das Überladen einer fehlerhaften Abhängigkeit. Sie können dieses Muster auch verwenden, um einen ordnungsgemäßen Abbau der Workload auszulösen. Trennschalter werden häufig mit der automatischen Wiederherstellung gekoppelt, um sowohl die Selbsterhaltung als auch die Selbstreparatur zu ermöglichen.

- RE:03 Fehlermodusanalyse
- RE:07 Vorübergehende Fehler
- RE:07 Selbsterhaltung
Die Leistungseffizienz hilft Ihrer Workload, Anforderungen effizient durch Optimierungen in Skalierung, Daten und Code zu erfüllen. Dieses Muster vermeidet den Ansatz vom Typ „Wiederholung bei Fehler“, der zu einer übermäßigen Ressourcenauslastung während der Abhängigkeitswiederherstellung führen und auch die Leistung einer Abhängigkeit überlasten kann, die eine Wiederherstellung versucht.

- PE:07 Code und Infrastruktur
- PE:11 Antworten auf Live-Probleme

Berücksichtigen Sie wie bei jeder Designentscheidung alle Kompromisse im Hinblick auf die Ziele der anderen Säulen, die mit diesem Muster eingeführt werden könnten.

Die folgenden Muster können für die Implementierung dieses Musters relevant sein:

  • Das Muster für zuverlässige Web-Apps zeigt, wie Sie das Trennschaltermuster auf Webanwendungen anwenden, die zur Cloud migriert werden.

  • Wiederholungsmuster: Beschreibt, wie eine Anwendung beim Herstellen einer Verbindung mit einem Dienst oder einer Netzwerkressource antizipierte, temporäre Fehler behandeln kann, indem ein zuvor nicht erfolgreich durchgeführter Vorgang transparent wiederholt wird.

  • Muster für Überwachung der Integrität von Endpunkten: Ein Trennschalter könnte in der Lage sein, den Zustand eines Diensts zu testen, indem er eine Anforderung an einen Endpunkt sendet, der durch den Dienst exponiert wird. Der Dienst sollte Informationen über seinen Zustand zurückgeben.