- Authors

- Name
- Phillip Pham
- @ddppham
Kubernetes Retry Pattern: Automatische Wiederholung bei Fehlern
TL;DR
- Transiente Fehler (Netzwerk-Timeouts, 503er, Connection Resets) werden durch Retries automatisch abgefangen, ohne dass Endnutzer etwas bemerken
- Drei Retry-Strategien: Immediate Retry, Fixed Delay und Exponential Backoff mit Jitter -- je nach Fehlertyp unterschiedlich geeignet
- Istio VirtualService und Envoy bieten Retry-Konfiguration auf Infrastrukturebene, komplett ohne Aenderung am Anwendungscode
- Retries ohne Idempotenz sind gefaehrlich und fuehren zu doppelten Bestellungen oder Buchungen
- Kombination mit Circuit Breaker verhindert, dass Retries ein bereits ueberlastetes System endgueltig zum Absturz bringen
Warum Retries in verteilten Systemen Pflicht sind
In einem Kubernetes-Cluster kommunizieren Dutzende bis Hunderte Services ueber das Netzwerk. Netzwerke sind nicht zuverlaessig. Pods werden neu geplant, Nodes verschwinden, Load Balancer verteilen Traffic auf Pods, die gerade hochfahren. Transiente Fehler sind der Normalfall, nicht die Ausnahme.
Ohne Retry-Logik fuehrt jeder dieser Fehler zu einem sichtbaren Problem fuer den Endnutzer. Mit einer durchdachten Retry-Strategie werden ueber 90 Prozent dieser Fehler unsichtbar abgefangen.
Das Problem: Naive Retries koennen die Situation verschlimmern. Wenn ein Service ueberlastet ist und 100 Clients gleichzeitig ihre fehlgeschlagenen Requests wiederholen, entsteht ein Retry Storm, der den Service endgueltig zum Absturz bringt.
Die drei Retry-Strategien im Vergleich
Immediate Retry
Der Request wird sofort erneut gesendet. Sinnvoll bei Connection Resets, wenn der Fehler durch einen kurzfristigen Zustand verursacht wurde. Risiko: Bei Ueberlast verschlimmert sofortiges Retry die Situation massiv.
Fixed Delay Retry
Zwischen den Versuchen liegt ein fester Zeitabstand, z.B. 500ms. Besser als Immediate Retry, aber alle Clients wiederholen gleichzeitig, wenn sie den ersten Fehler gleichzeitig bekamen.
Exponential Backoff mit Jitter (Best Practice)
Der Abstand zwischen Versuchen verdoppelt sich mit jedem Versuch, plus eine zufaellige Komponente (Jitter). Das verteilt die Retry-Last ueber die Zeit und verhindert Thundering-Herd-Effekte.
| Strategie | Verzoegerung | Einsatz | Risiko |
|---|---|---|---|
| Immediate | 0ms | Connection Reset | Retry Storm bei Ueberlast |
| Fixed Delay | 500ms fest | Kurze Ausfaelle | Synchronisierte Retries |
| Exponential Backoff | 100ms, 200ms, 400ms | Allgemein empfohlen | Laengere Gesamtwartezeit |
| Backoff mit Jitter | 100ms +/- 50ms, variabel | Best Practice | Minimal |
Retry auf Infrastrukturebene mit Istio
Der groesste Vorteil eines Service Mesh: Retry-Logik wird aus dem Anwendungscode herausgehalten und zentral konfiguriert. Jeder Envoy Sidecar fuehrt Retries automatisch durch.
Mehr zu Istio-Konfiguration in Kubernetes-Umgebungen findet sich im Beitrag zu Istio Ambient Mesh.
Istio VirtualService mit Retry-Policy
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: order-service
namespace: production
spec:
hosts:
- order-service
http:
- route:
- destination:
host: order-service
port:
number: 8080
retries:
attempts: 3
perTryTimeout: 2s
retryOn: "5xx,reset,connect-failure,retriable-4xx"
timeout: 10s
Die wichtigen Parameter im Detail:
- attempts: Maximale Anzahl Wiederholungsversuche (hier 3, also insgesamt 4 Versuche)
- perTryTimeout: Timeout fuer jeden einzelnen Versuch
- retryOn: Welche Fehler einen Retry ausloesen
- timeout: Gesamttimeout fuer alle Versuche zusammen
Envoy Retry-Bedingungen
| Bedingung | Wann wird retried |
|---|---|
5xx | Bei allen Server-Fehlern (500-599) |
reset | Bei TCP Connection Reset |
connect-failure | Wenn der Verbindungsaufbau fehlschlaegt |
retriable-4xx | Bei 409 Conflict |
gateway-error | Bei 502, 503, 504 |
refused-stream | Bei HTTP/2 REFUSED_STREAM |
Erweiterte Backoff-Konfiguration mit EnvoyFilter
Fuer feinere Kontrolle ueber Backoff-Parameter laesst sich ein EnvoyFilter einsetzen:
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: retry-backoff-config
namespace: production
spec:
workloadSelector:
labels:
app: order-service
configPatches:
- applyTo: HTTP_ROUTE
match:
context: SIDECAR_OUTBOUND
patch:
operation: MERGE
value:
route:
retry_policy:
retry_back_off:
base_interval: 100ms
max_interval: 1s
num_retries: 3
retry_on: "5xx,connect-failure,refused-stream"
Der base_interval definiert den Startwert fuer den Exponential Backoff. Envoy verdoppelt diesen Wert mit jedem Versuch bis zum max_interval. Zusaetzlich fuegt Envoy automatisch Jitter hinzu.
Retry auf Anwendungsebene
Infrastruktur-Retries decken HTTP-basierte Kommunikation ab. Fuer Datenbank-Verbindungen, Message-Queue-Operationen oder komplexe Ablaeufe braucht man Retries im Anwendungscode.
Go: Retry mit Exponential Backoff
func retryWithBackoff(ctx context.Context, maxRetries int, fn func() error) error {
baseDelay := 100 * time.Millisecond
maxDelay := 10 * time.Second
for attempt := 0; attempt <= maxRetries; attempt++ {
err := fn()
if err == nil {
return nil
}
if !isRetryable(err) {
return err
}
if attempt == maxRetries {
return fmt.Errorf("max retries exceeded: %w", err)
}
delay := time.Duration(math.Pow(2, float64(attempt))) * baseDelay
if delay > maxDelay {
delay = maxDelay
}
jitter := time.Duration(rand.Int63n(int64(delay / 2)))
delay += jitter
select {
case <-ctx.Done():
return ctx.Err()
case <-time.After(delay):
}
}
return nil
}
Java: Resilience4j Retry
RetryConfig retryConfig = RetryConfig.custom()
.maxAttempts(3)
.waitDuration(Duration.ofMillis(500))
.intervalFunction(IntervalFunction.ofExponentialBackoff(500, 2.0))
.retryOnException(e -> e instanceof ServiceUnavailableException)
.ignoreExceptions(BadRequestException.class)
.build();
Retry retry = Retry.of("orderService", retryConfig);
Supplier<Order> decoratedSupplier = Retry.decorateSupplier(
retry, () -> orderClient.createOrder(request)
);
Try.ofSupplier(decoratedSupplier)
.recover(MaxRetriesExceededException.class, e -> fallbackOrder());
Idempotenz: Die Voraussetzung fuer sichere Retries
Retries bedeuten, dass ein Request mehrfach beim Zielservice ankommen kann. Ohne Idempotenz fuehrt das zu Problemen:
| Operation | Idempotent? | Retry sicher? |
|---|---|---|
| GET /orders/123 | Ja | Ja |
| PUT /orders/123 (vollstaendig) | Ja | Ja |
| DELETE /orders/123 | Ja | Ja |
| POST /orders (neue Bestellung) | Nein | Gefaehrlich |
| PATCH /orders/123 (Menge +1) | Nein | Gefaehrlich |
Fuer nicht-idempotente Operationen gibt es eine bewaehrte Loesung: Idempotency Keys. Der Client sendet einen eindeutigen Key mit jedem Request. Der Server prueft vor der Ausfuehrung, ob dieser Key bereits verarbeitet wurde.
apiVersion: v1
kind: ConfigMap
metadata:
name: idempotency-config
namespace: production
data:
config.yaml: |
idempotency:
header_name: "Idempotency-Key"
store: redis
ttl: 24h
redis_host: "redis-master.production.svc.cluster.local:6379"
Circuit Breaker Integration
Retries allein reichen nicht. Wenn ein Service dauerhaft ausfaellt, produzieren Retries nur zusaetzliche Last. Ein Circuit Breaker erkennt, wann ein Service nicht mehr reagiert, und stoppt weitere Aufrufe.
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: order-service
namespace: production
spec:
host: order-service
trafficPolicy:
connectionPool:
tcp:
maxConnections: 100
http:
h2UpgradePolicy: DEFAULT
http1MaxPendingRequests: 50
http2MaxRequests: 200
outlierDetection:
consecutive5xxErrors: 5
interval: 10s
baseEjectionTime: 30s
maxEjectionPercent: 50
Die outlierDetection konfiguriert den Circuit Breaker. Nach 5 aufeinanderfolgenden 5xx-Fehlern wird der betroffene Pod fuer 30 Sekunden aus dem Load Balancing entfernt. Retries werden dann automatisch an gesunde Pods gelenkt.
Mehr dazu im Beitrag zu Resilience Patterns in Kubernetes.
Monitoring von Retries
Retries, die unsichtbar im Hintergrund ablaufen, sind gefaehrlich, wenn man sie nicht ueberwacht. Drei Metriken sind essentiell:
- Retry-Rate: Wie viele Requests brauchen mindestens einen Retry? Steigt diese Rate, deutet das auf ein Problem hin
- Retry-Erfolgsrate: Wie viele Retries fuehren letztendlich zum Erfolg? Eine niedrige Rate bedeutet, dass Retries sinnlos Last erzeugen
- Latenz-Overhead: Wie viel laenger dauern Requests mit Retries im Vergleich?
# Retry-Statistiken eines Pods abfragen
kubectl exec -n production deploy/order-service -c istio-proxy -- \
curl -s localhost:15000/stats | grep retry
# Wichtige Metriken:
# upstream_rq_retry -- Gesamtzahl der Retries
# upstream_rq_retry_success -- Erfolgreiche Retries
# upstream_rq_retry_overflow -- Retries die das Budget ueberschritten
# upstream_rq_retry_limit_exceeded -- Retries ueber dem Maximum
Fuer die Grundlage zuverlaessiger Health Checks im Zusammenspiel mit Retries empfiehlt sich der Beitrag zu Kubernetes Health Checks und Probes.
Best Practices
Maximal 3 Retries: Mehr als 3 Retries bringen selten Erfolg und erhoehen die Gesamtlatenz erheblich. Wenn nach 4 Versuchen keine Antwort kommt, liegt kein transienter Fehler vor.
Gesamttimeout setzen: Retries mit Exponential Backoff koennen sich aufaddieren. Ein Gesamttimeout von 10-15 Sekunden verhindert endloses Warten.
Nur retriable Fehler wiederholen: 400 Bad Request oder 404 Not Found werden durch Wiederholen nicht besser. Retries nur bei 5xx, Timeouts und Connection-Fehlern.
Jitter immer aktivieren: Ohne Jitter wiederholen alle Clients zur exakt gleichen Zeit und erzeugen periodische Lastspitzen.
Retry-Budget definieren: Maximal 20 Prozent des gesamten Traffics duerfen Retries sein. Wird das Budget ueberschritten, werden Retries temporaer deaktiviert.
Fuer eine umfassende Uebersicht zu Service-Kommunikation in Kubernetes empfiehlt sich der Beitrag zu Kubernetes Service Discovery.
Haeufige Fehler bei der Implementierung
Retry auf beiden Ebenen: Wenn sowohl die Anwendung als auch Istio Retries durchfuehren, multiplizieren sich die Versuche. 3 App-Retries mal 3 Istio-Retries ergibt 9 Versuche. Entscheidet euch fuer eine Ebene.
Kein Backoff: Sofortige Retries ohne Verzoegerung ueberlasten den Zielservice. Exponential Backoff ist kein Nice-to-have, sondern Pflicht.
Retry bei nicht-idempotenten Operationen: POST-Requests ohne Idempotency-Key zu wiederholen fuehrt zu doppelten Daten. Prueft die Idempotenz, bevor ihr Retries aktiviert.
Retries ohne Monitoring: Retries kaschieren Probleme. Ohne Metriken bemerkt man nicht, dass ein Service seit Wochen instabil ist und nur durch Retries am Laufen gehalten wird.
Zusammenfassung
Das Retry Pattern ist eine der grundlegendsten Resilience-Massnahmen in Kubernetes-Umgebungen. Mit Istio und Envoy laesst es sich auf Infrastrukturebene umsetzen, ohne Anwendungscode anzupassen. Fuer Datenbank- und Message-Queue-Operationen braucht man zusaetzlich Retries im Code.
Die drei wichtigsten Regeln: Exponential Backoff mit Jitter verwenden, Idempotenz sicherstellen und Retries mit einem Circuit Breaker kombinieren. Ohne diese Grundlagen richten Retries mehr Schaden an, als sie verhindern.
Wenn Sie Unterstuetzung bei der Implementierung von Retry-Strategien in Ihrer Kubernetes-Umgebung benoetigen, kontaktieren Sie uns unter /kontakt.
Kubernetes-Beratung gesucht?
Wir helfen deutschen Unternehmen bei der Kubernetes-Implementierung, Migration und Optimierung. DSGVO-konform und praxiserprobt.
📖 Verwandte Artikel
Weitere interessante Beiträge zu ähnlichen Themen
Resilience Patterns für Kubernetes Microservices
Resilience Patterns für Kubernetes-Microservices: Retry, Circuit Breaker, Bulkhead, Timeout, Health Checks und PDB mit YAML-Konfigurationen.
Kubernetes Deutschland: Retry Pattern für resiliente Systeme
Erfahren Sie, wie das Retry Pattern die Resilienz und Fehlertoleranz von Kubernetes-Anwendungen in Deutschland optimiert. Steigern Sie die Verfügbarkeit Ihrer Systeme und gewährleisten Sie mit intelligenten Wiederholungsstrategien eine robuste Performance auch in anspruchsvollen Umgebungen.
Istio Service Mesh auf Kubernetes einrichten
Istio Service Mesh auf Kubernetes installieren und konfigurieren: Sidecar-Injection, Traffic-Routing mit VirtualService und mTLS zwischen Services.
Kubernetes Bulkhead Pattern: Service-Isolation einrichten
Bulkhead Pattern in Kubernetes umsetzen: ResourceQuotas, LimitRanges, Node-Pool-Trennung und Istio Connection Pools für zuverlässige Fehlerisolation.
Kubernetes Circuit Breaker mit Istio: Resilienz-Patterns
Circuit Breaker, Retry, Timeout und Bulkhead in Kubernetes mit Istio implementieren: Envoy-Konfiguration und Praxisbeispiele gegen Kaskadenausfälle.