Resilienz-Patterns
In verteilten Systemen sind Fehler normal.
Resilienz bedeutet nicht, Fehler zu verhindern.
Resilienz bedeutet, Fehler kontrolliert zu begrenzen – technisch und fachlich.
Ohne Resilienz werden Microservices zu:
- Cascading Failures (Kettenreaktion)
- Retry-Stürmen (Lastverstärkung)
- Totalausfällen durch Teilkomponenten
- “Degradation ohne Sichtbarkeit” (alles wird langsam, niemand weiß warum)
Grundprinzipien
1) Jeder Remote Call ist unsicher
Netzwerk, DNS, TLS, Queues, Dependencies: alles kann langsam werden oder ausfallen.
Jede Abhängigkeit braucht eine Schutzstrategie – standardisiert, dokumentiert, messbar.
2) Resilienz ist Policy, nicht “Best Effort”
Wenn jedes Team Resilienz “ein bisschen anders” macht, entsteht Chaos. Resilienz gehört zu euren Plattform-/Architektur-Standards.
3) Beobachtbarkeit ist Teil der Resilienz
Resilienz ohne Telemetrie ist Glücksspiel:
Timeouts, Retries, Circuit States, Fallback-Rate müssen sichtbar sein.
Basis-Patterns (Minimum-Standard)
Diese Seite beschreibt das Minimum. Die Details findest du in den Einzelpattern-Seiten (z. B. Circuit Breaker, Retry/Backoff, Rate Limiting, Idempotency).
1️⃣ Timeout & Cancellation
Kein Remote Call ohne:
- festes Timeout (connect + request)
- Cancellation / Abbruchstrategie
- saubere Ressourcenfreigabe
Faustregel: Timeouts sind Budgets – sie müssen zur User Journey passen.
Anti-Pattern: Default-Timeouts des Clients “einfach so” übernehmen.
2️⃣ Retry mit Exponential Backoff (+ Jitter)
Geeignet für:
- transiente Fehler
- Netzwerk-Hiccups
- kurzzeitige Überlast
Nicht geeignet für:
- dauerhafte Fehler
- Validierungsfehler
- Business-Regel-Verletzungen
- nicht-idempotente Operations (ohne Idempotency-Key)
Pflichtregeln:
- begrenzte Retries (z. B. 2–3)
- Backoff + Jitter (gegen Synchron-Retry-Stürme)
- Retries nur bei klar definierten Fehlerklassen (z. B. 5xx, Timeout)
3️⃣ Circuit Breaker
Ziel: Stoppe sinnlose Calls gegen instabile Dependencies.
Zustände:
- Closed (normal)
- Open (blockiert)
- Half-Open (Probe)
Pflicht: Circuit States und Open-Rate müssen als Metrik existieren.
4️⃣ Bulkhead (Ressourcen-Isolation)
Isolation von Ressourcen, z. B.:
- separate Thread-/Worker-Pools
- Concurrency Limits
- getrennte Connection-Pools
- Queue-isolierte Worker
Ziel: ein langsamer Dependency-Pfad darf nicht alles blockieren.
Bulkhead verhindert, dass ein Leck das ganze Schiff flutet.
5️⃣ Fallback / Graceful Degradation
Nicht jede Funktion ist kritisch.
Beispiele:
- Empfehlungen anzeigen → optional
- Checkout/Payment → kritisch
Fallback kann sein:
- Cache (stale-while-revalidate)
- reduzierte Antwort (Partial Response)
- Default-Wert / “Feature temporär nicht verfügbar”
- alternative Strecke (z. B. anderer Provider)
Pflicht: Fallback-Raten müssen sichtbar sein (sonst “schleichender Defekt”).
Referenzfluss (Synchron)
Interpretation:
- Timeout schützt Ressourcen
- Retry behandelt temporäre Fehler (nur kontrolliert)
- Circuit Breaker schützt System vor Kaskaden
- Fallback schützt die Nutzererfahrung
Resilienz in asynchronen Systemen
Asynchron reduziert Laufzeitkopplung, erhöht aber Zustands- und Wiederholungslogik.
Zusätzliche Standards:
- Dead Letter Queue (DLQ) + klare Policy (wann rein, wann raus)
- Idempotenz (Consumer müssen Redelivery vertragen)
- Retry/Backoff auf Consumer-Seite (mit Rate/Concurrency Limits)
- Replay-Strategie (reprocess ohne Chaos)
- Poison-Message Handling (Quarantäne, Monitoring, Alert)
Mindest-Gates für produktive Microservices
Remote Calls
- Jeder Remote Call hat ein Timeout (Budget dokumentiert).
- Retry-Strategie ist definiert (Backoff + Jitter + max attempts).
- Circuit Breaker Policy existiert (inkl. Monitoring).
Isolation
- Bulkhead/Concurrency Limits sind umgesetzt oder begründet abgewählt.
Degradation
- Fallback-Verhalten ist bewusst entschieden (pro Dependency/Journey).
- Fallback-Rate ist als Metrik vorhanden.
Testing
- Resilienz ist getestet (Failure-/Chaos-Tests oder Dependency-Simulation).
- Critical Journeys haben definierte SLOs und Alerts.
Typische Anti-Patterns
- Retry ohne Backoff/Jitter
- Retry bei permanenten Fehlern
- Kein Timeout (“hängt halt manchmal”)
- Globale Thread-Pools / keine Concurrency Limits
- Circuit Breaker ohne Telemetrie
- Fallback ohne Monitoring (versteckte Degradation)
- “Wir haben Service Mesh, also brauchen wir nichts im Code” (falsch: Semantik bleibt fachlich)
Fazit
Microservices ohne Resilienz sind operativ riskant:
- fragil
- teuer im Incident-Handling
- schwer zu skalieren
Resilienz ist das Gegenstück zur Verteilung. Wer verteilt, muss isolieren – und messbar degradieren können.