Circuit Breaker
Wenn ein System einen externen Dienst aufruft und dieser nicht antwortet, warten alle nachfolgenden Anfragen ebenfalls. Binnen Sekunden staut sich die Last, bis das gesamte System steht. Ein Schutzmechanismus erkennt dieses Muster und unterbricht die Verbindung, bevor der Fehler sich ausbreitet. Dieses Prinzip heißt Circuit Breaker.
Warum Systeme ohne Schutz kaskadierend ausfallen
Verteilte Systeme bestehen aus Diensten, die sich gegenseitig aufrufen. Wenn Dienst B nicht antwortet, hält Dienst A einen Thread offen und wartet. Jede neue Anfrage an Dienst A erzeugt einen weiteren wartenden Thread. Sobald alle verfügbaren Threads belegt sind, kann Dienst A selbst keine Anfragen mehr annehmen. Dienst C, der wiederum von Dienst A abhängt, erfährt dasselbe Schicksal. Aus dem Ausfall eines einzigen Dienstes wird ein systemweiter Zusammenbruch.
Beispiel: Ein Online-Shop ruft einen Zahlungsdienstleister auf. Der Zahlungsdienst antwortet nicht mehr. Jede Bestellanfrage blockiert nun 30 Sekunden im Timeout. Nach 200 gleichzeitigen Bestellungen sind alle Threads des Shop-Servers belegt. Die Produktsuche, das Nutzerprofil und der Warenkorb werden ebenfalls unerreichbar, obwohl diese Funktionen den Zahlungsdienst gar nicht benötigen.
Beispiel: Ein KI-gestützter Chatbot sendet Nutzeranfragen an eine API für Sprachmodelle. Die API drosselt Anfragen wegen Überlastung. Ohne Schutzmechanismus versucht der Chatbot weiterhin, jede Nachricht an die API zu senden. Die Antwortzeiten steigen auf Minuten. Nutzer brechen ab und starten neue Sessions, was die Last weiter erhöht.
Dieses Verhalten heißt Kaskadenfehler: Ein lokaler Ausfall pflanzt sich über Abhängigkeitsketten durch das gesamte System fort.
Drei Zustände: geschlossen, offen, halboffen
Der Circuit Breaker arbeitet als Zustandsautomat zwischen dem aufrufenden Code und dem externen Dienst. Er kennt drei Zustände:
Geschlossen (Closed): Alle Anfragen werden an den externen Dienst weitergeleitet. Der Circuit Breaker zählt Fehler mit. Solange die Fehlerrate unter einem konfigurierten Schwellenwert bleibt, geschieht nichts. Das ist der Normalzustand.
Offen (Open): Die Fehlerrate hat den Schwellenwert überschritten. Der Circuit Breaker blockiert alle weiteren Anfragen sofort, ohne den externen Dienst zu kontaktieren. Stattdessen gibt er eine definierte Fehlerantwort oder einen Fallback-Wert zurück. Dieser Zustand schützt sowohl das eigene System (keine blockierten Threads) als auch den ausgefallenen Dienst (keine zusätzliche Last während der Erholungsphase).
Halboffen (Half-Open): Nach einer konfigurierten Wartezeit lässt der Circuit Breaker eine einzelne Testanfrage durch. Gelingt diese, wechselt er zurück in den geschlossenen Zustand. Schlägt sie fehl, bleibt er offen und startet die Wartezeit erneut.
Beispiel: Ein Empfehlungsdienst ruft ein ML-Modell auf, das Produktvorschläge berechnet. Der Circuit Breaker ist auf einen Schwellenwert von 5 Fehlern in 10 Sekunden konfiguriert. Nach dem fünften Timeout öffnet er. 60 Sekunden lang erhält jeder Aufruf stattdessen eine statische Liste der meistverkauften Produkte. Dann sendet der Circuit Breaker eine einzelne Testanfrage. Antwortet das Modell, schließt der Breaker wieder.
Schwellenwerte und Zeitfenster konfigurieren
Die Wirksamkeit eines Circuit Breakers hängt von der Konfiguration ab. Zwei Parameter sind zentral: der Fehler-Schwellenwert und das Zeitfenster, in dem Fehler gezählt werden.
Ein zu niedriger Schwellenwert öffnet den Breaker bei einzelnen, vorübergehenden Fehlern. Ein zu hoher Schwellenwert lässt zu viele fehlerhafte Anfragen durch, bevor der Schutz greift. Ein zu kurzes Zeitfenster vergisst Fehler zu schnell. Ein zu langes Zeitfenster akkumuliert Fehler über lange Zeiträume, die keinen tatsächlichen Ausfall darstellen.
Beispiel: Ein System kommuniziert mit einer Drittanbieter-API, die im Normalbetrieb bei 0,1 Prozent der Anfragen Fehler zurückgibt. Der Schwellenwert steht auf "3 Fehler in 60 Sekunden". Bei 5.000 Anfragen pro Minute treten statistisch 5 Fehler auf. Der Breaker öffnet also auch im Normalbetrieb. Der Schwellenwert muss an das Grundrauschen angepasst werden.
Beispiel: Ein Circuit Breaker vor einer LLM-API zählt nur HTTP-5xx-Fehler, keine 429-Responses (Rate Limiting). Die Unterscheidung ist relevant: Bei Rate Limiting hilft eine exponentielle Verzögerung zwischen Anfragen. Bei Serverfehlern hilft das Unterbrechen der Verbindung.
In der Praxis bewegen sich übliche Werte zwischen 5 und 20 Fehlern in einem Fenster von 10 bis 60 Sekunden. Die Wartezeit im offenen Zustand liegt häufig zwischen 30 und 120 Sekunden. Diese Werte sind Ausgangspunkte, keine Universallösungen.
Fachliche Einordnung: Die Konfiguration von Schwellenwerten ist ein Optimierungsproblem unter Unsicherheit. Zu aggressive Einstellungen führen zu unnötigen Unterbrechungen (False Positives). Zu konservative Einstellungen lassen Kaskadeneffekte zu (False Negatives). In der Literatur wird dies als Spannungsfeld zwischen Verfügbarkeit und Schutz beschrieben. Adaptive Circuit Breaker passen Schwellenwerte auf Basis historischer Fehlerraten dynamisch an.
Fallback-Strategien: Was geschieht, wenn der Breaker offen ist
Ein geöffneter Circuit Breaker muss dem aufrufenden Code eine Antwort liefern. Die einfachste Variante: eine Fehlermeldung. Oft ist das nicht ausreichend. Ein System kann mit reduzierten Daten besser arbeiten als mit gar keinen.
Beispiel: Ein Nachrichtenportal generiert personalisierte Schlagzeilen über ein Sprachmodell. Der Circuit Breaker öffnet, weil die Modell-API nicht antwortet. Der Fallback liefert die redaktionell erstellten Standardschlagzeilen. Die Personalisierung fehlt, aber die Seite bleibt funktional.
Beispiel: Eine Suchfunktion nutzt ein Embedding-Modell für semantische Suche. Bei geöffnetem Breaker schaltet das System auf eine klassische Volltextsuche um. Die Ergebnisqualität sinkt, aber die Suche liefert weiterhin Treffer.
Typische Fallback-Strategien:
Cache-basierter Fallback: Das System gibt die letzte erfolgreiche Antwort für denselben oder einen ähnlichen Request zurück. Bei Empfehlungssystemen oder Konfigurationsdiensten ist das häufig akzeptabel.
Default-Wert: Ein statischer, vordefinierter Rückgabewert. Bei Feature-Flags etwa ein konservativer Standardwert, der neue Features deaktiviert.
Degraded Mode: Das System bietet eingeschränkte Funktionalität. Ein KI-gestützter Assistent antwortet mit vorformulierten Textbausteinen statt mit generierten Antworten.
Beispiel: Ein RAG-System ruft zur Laufzeit ein Sprachmodell und eine Vektordatenbank auf. Der Circuit Breaker vor der Vektordatenbank öffnet. Der Fallback: Das System durchsucht einen vorindizierten Keyword-Index statt der Vektordatenbank. Die Relevanz der Ergebnisse sinkt, aber das System liefert weiterhin Antworten.
Implementierung in der Praxis
Circuit Breaker existieren als eigenständige Bibliotheken oder als Bestandteil größerer Resilience-Frameworks. In Java ist Resilience4j die verbreitete Wahl, in Python pybreaker, in Go gobreaker. Auf Infrastrukturebene implementieren Service Meshes wie Istio oder Linkerd Circuit Breaker als Sidecar-Proxies, ohne dass Anwendungscode geändert werden muss.
Beispiel: Ein Python-Dienst ruft eine LLM-API auf. Mit pybreaker sieht die Implementierung so aus: Der Circuit Breaker wird mit fail_max=5 und reset_timeout=60 konfiguriert. Ein Dekorator @circuit_breaker wrapping die Aufruffunktion. Bei fünf aufeinanderfolgenden Fehlern blockiert der Breaker weitere Aufrufe für 60 Sekunden. Der aufrufende Code fängt eine CircuitBreakerError-Exception und aktiviert den Fallback.
Auf Infrastrukturebene arbeiten Service Meshes anders. Istio konfiguriert Circuit Breaker über eine DestinationRule-Ressource. Parameter wie consecutiveErrors, interval und baseEjectionTime steuern das Verhalten. Der Vorteil: Die Anwendung selbst bleibt unverändert. Der Nachteil: Die Konfiguration erfolgt deklarativ auf Infrastrukturebene und ist von der Anwendungslogik entkoppelt. Fallback-Strategien müssen trotzdem im Anwendungscode implementiert werden.
Beispiel: Ein Microservice-System nutzt Istio. Der Circuit Breaker öffnet, wenn 5 aufeinanderfolgende 5xx-Fehler auftreten. Die betroffene Instanz wird für 30 Sekunden aus dem Load-Balancing-Pool entfernt. Anfragen werden auf gesunde Instanzen umgeleitet. Der Mechanismus arbeitet auf Instanzebene, nicht auf Dienstebene.
Circuit Breaker in KI-Systemen
KI-Systeme haben spezifische Fehlercharakteristiken, die sich von klassischen Webdiensten unterscheiden. LLM-APIs antworten langsam (Sekunden statt Millisekunden). Timeouts müssen entsprechend höher liegen. Rate Limiting ist bei kommerziellen APIs der Regelfall, nicht die Ausnahme. Modell-Inferenz kann sporadisch fehlschlagen, ohne dass die API selbst ausfällt.
Beispiel: Ein System nutzt ein großes Sprachmodell für die Zusammenfassung von Dokumenten. Die API antwortet im Normalbetrieb in 3 bis 8 Sekunden. Ein Standard-Timeout von 5 Sekunden würde bei längeren Dokumenten regelmäßig auslösen. Der Circuit Breaker muss zwischen echten Ausfällen und erwartbar langen Antwortzeiten unterscheiden. Eine Lösung: adaptive Timeouts, die sich an der durchschnittlichen Antwortzeit der letzten Minuten orientieren.
Beispiel: Ein Prompt-Engineering-Werkzeug testet verschiedene Prompt-Varianten gegen eine API. Bei Rate Limiting (HTTP 429) soll der Circuit Breaker nicht sofort öffnen, sondern die Anfragerate drosseln. Nur bei wiederholten Serverfehlern (HTTP 5xx) soll er die Verbindung unterbrechen. Die Fehlerklassifikation wird zum zentralen Konfigurationselement.
Bei Multi-Provider-Architekturen schützt ein Circuit Breaker pro Provider. Fällt Provider A aus, leitet das System Anfragen an Provider B um. Dieses Muster heißt Provider Failover und kombiniert Circuit Breaker mit Load Balancing.
Abgrenzung zu verwandten Mustern
Circuit Breaker sind ein Baustein unter mehreren Resilience-Patterns. Sie überschneiden sich mit Retry, Timeout, Bulkhead und Rate Limiter. Die Abgrenzung ist wichtig, weil diese Muster sich ergänzen, nicht ersetzen.
Retry wiederholt eine fehlgeschlagene Anfrage. Ein Circuit Breaker unterdrückt Anfragen. Beide zusammen: Retry versucht es einige Male. Wenn die Retries scheitern, öffnet der Circuit Breaker und verhindert weitere Versuche für eine definierte Zeitspanne.
Timeout begrenzt die Wartezeit einer einzelnen Anfrage. Ein Circuit Breaker reagiert auf Fehlerhäufungen über mehrere Anfragen. Ohne Timeout würde der Circuit Breaker Fehler nicht zählen können, weil die Anfragen nie zurückkehren.
Bulkhead isoliert Ressourcen. Ein Thread-Pool pro externem Dienst verhindert, dass ein langsamer Dienst alle Threads belegt. Der Circuit Breaker ergänzt das Bulkhead, indem er Anfragen an einen ausgefallenen Dienst gar nicht erst zulässt.
Beispiel: Ein System kombiniert alle vier Muster. Timeout: 10 Sekunden pro Anfrage. Retry: 2 Wiederholungen mit exponentiellem Backoff. Circuit Breaker: Öffnet nach 5 Fehlern in 30 Sekunden, Wartezeit 60 Sekunden. Bulkhead: Maximal 20 gleichzeitige Verbindungen pro Dienst. Die Reihenfolge der Ausführung: Bulkhead begrenzt die Parallelität, Circuit Breaker prüft den Zustand, Timeout begrenzt die Wartezeit, Retry wiederholt bei Bedarf.
Fachliche Einordnung: Michael Nygard beschrieb das Circuit-Breaker-Pattern 2007 in "Release It!". Martin Fowler machte es 2014 mit seinem vielzitierten Artikel einem breiteren Publikum zugänglich. In der Praxis hat Netflix mit der Hystrix-Bibliothek (2012, inzwischen im Wartungsmodus) die Verbreitung im Microservice-Kontext maßgeblich vorangetrieben. Resilience4j gilt als Nachfolger in der Java-Welt.
Beobachtbarkeit: Circuit Breaker überwachen
Ein Circuit Breaker, der unbemerkt öffnet, verfehlt seinen Zweck. Teams müssen wissen, wann ein Breaker den Zustand wechselt, wie häufig er öffnet und wie lange er offen bleibt.
Die relevanten Metriken: Anzahl der Zustandsübergänge (closed → open, half-open → closed, half-open → open), Dauer im offenen Zustand, Fehlerrate im geschlossenen Zustand, Anteil der Anfragen die vom Fallback bedient werden.
Beispiel: Ein Prometheus-Dashboard zeigt die Fehlerrate eines Dienstes. Um 14:23 Uhr steigt die Rate auf 40 Prozent. Der Circuit Breaker öffnet. Ein Alert benachrichtigt das Team. Das Dashboard zeigt, dass der Breaker nach 60 Sekunden in den halboffenen Zustand wechselt, eine Testanfrage sendet und wieder öffnet. Erst nach dem dritten Zyklus, um 14:26 Uhr, schließt er dauerhaft. Das Team untersucht rückblickend die drei Minuten Ausfall und passt die Konfiguration an.
Beispiel: Ein System protokolliert jeden Zustandswechsel als strukturiertes Log-Event mit Feldern für Dienst, vorheriger Zustand, neuer Zustand, Fehleranzahl und Zeitstempel. Diese Events fließen in ein zentrales Logging-System. Ein automatischer Report zeigt wöchentlich, welche Circuit Breaker am häufigsten geöffnet haben. Dienste mit hoher Öffnungsfrequenz werden priorisiert für Stabilitätsverbesserungen.
Grenzen und typische Fehler
Circuit Breaker lösen nicht alle Verfügbarkeitsprobleme. Sie schützen vor kaskadierenden Ausfällen, aber nicht vor logischen Fehlern. Wenn ein Dienst fehlerhafte Daten zurückgibt, ohne einen HTTP-Fehlercode zu senden, erkennt der Circuit Breaker das nicht.
Beispiel: Ein Sprachmodell generiert bei Überlastung kürzere, qualitativ schlechtere Antworten, gibt aber HTTP 200 zurück. Der Circuit Breaker bleibt geschlossen, weil keine technischen Fehler auftreten. Die Qualitätsverschlechterung bleibt unbemerkt, solange keine zusätzliche Qualitätsprüfung implementiert ist.
Ein häufiger Fehler in der Praxis: Circuit Breaker werden implementiert, aber nicht getestet. Im Normalbetrieb sind sie unsichtbar. Erst bei einem Ausfall zeigt sich, ob die Konfiguration stimmt und der Fallback funktioniert. Chaos-Engineering-Methoden (kontrolliertes Auslösen von Fehlern in Produktionsumgebungen) adressieren dieses Problem.
Beispiel: Ein Team konfiguriert einen Circuit Breaker mit einer Wartezeit von 5 Minuten. Im Test funktioniert das. In der Produktion fällt auf, dass der externe Dienst sich typischerweise innerhalb von 15 Sekunden erholt. Die Wartezeit ist zu lang. Das System liefert 4 Minuten und 45 Sekunden unnötig lange Fallback-Antworten. Die Konfiguration muss an das tatsächliche Erholungsverhalten des Dienstes angepasst werden.
Ein weiteres Risiko: Wenn alle Instanzen eines Dienstes denselben Circuit Breaker teilen (Global State), kann eine einzelne fehlerhafte Instanz den Breaker für alle Instanzen öffnen. Die Lösung: Circuit Breaker pro Instanz oder eine anteilige Fehlerzählung, die die Gesamtheit der Instanzen berücksichtigt.
Fachliche Einordnung: Circuit Breaker sind ein reaktives Muster. Sie reagieren auf bereits eingetretene Fehler. Proaktive Ansätze wie Health Checks, Canary Deployments und Load Shedding ergänzen sie, indem sie Probleme erkennen oder vermeiden, bevor Fehler beim Aufrufer ankommen. Ein robustes System kombiniert beide Ansätze.