Resilienz: Circuit Breaker und Retries
Systeme auch bei Teilausfällen stabil halten
Resilienz: Circuit Breaker und Retries ist eine kostenlose PHP Academy-Lektion auf CoddyKit. Dies ist Lektion 4 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des PHP Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der PHP Academy-Kurs umfasst insgesamt 4 Lektionen.
Resilienz-Muster
In einem verteilten System sind Teilausfälle der Normalfall – irgendeine Abhängigkeit ist immer langsam, wird neu gestartet oder ist überlastet. Bei Resilienz geht es darum, jeden Service so zu entwerfen, dass eine beeinträchtigte Abhängigkeit nicht den Service und anschließend das gesamte System mit sich zu Fall bringt.
Diese Lektion behandelt die wichtigsten Werkzeuge: Timeouts, Retries mit Backoff, Circuit Breaker, Bulkheads und Graceful Degradation – alles mit PHP.
Timeouts zuerst
Die wichtigste einzelne Einstellung für Resilienz ist das Timeout. Ohne Timeout hält ein langsamer nachgelagerter Service Ihre PHP-FPM-Worker fest; Anfragen stauen sich; Ihnen gehen die Worker aus; Ihr Service fällt aus, nur weil jemand anderes langsam war. Das ist der klassische kaskadierende Ausfall.
Setzen Sie bei jedem ausgehenden Aufruf sowohl ein Verbindungs- als auch ein Gesamt-Timeout. Immer.
<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
$http = new Client([
'connect_timeout' => 0.5, // fail fast if we can't even connect
'timeout' => 2.0, // hard cap on the whole call
]);
// A hung dependency now fails in 2s instead of holding a worker forever.Retries – mit Bedacht
Vorübergehende Fehler (ein kurzer Aussetzer, ein kurzer Netzwerkausfall, ein 503) lassen sich bei einem zweiten Versuch oft beheben. Retries sind jedoch gefährlich: Wenn Sie zu bereitwillig wiederholen, verstärken Sie die Last auf einem ohnehin angeschlagenen Service. Regeln:
- Wiederholen Sie nur idempotente Operationen und bei wiederholbaren Fehlern (Timeouts, 5xx, 429).
- Begrenzen Sie die Anzahl der Versuche.
- Wiederholen Sie niemals 4xx-Clientfehler – sie werden einfach erneut fehlschlagen.
Exponentielles Backoff + Jitter
Retries in festen Intervallen synchronisieren sich bei vielen Clients zu einer thundering herd, die den sich erholenden Service in Wellen bombardiert. Die Lösung ist exponentielles Backoff (die Verzögerung bei jedem Versuch verdoppeln) plus Jitter (zufällige Abweichungen), um die Last zu verteilen.
<?php
function backoffDelay(int $attempt, float $base = 0.1, float $cap = 5.0): float {
$exp = min($cap, $base * (2 ** $attempt)); // 0.1, 0.2, 0.4, ...
return mt_rand(0, (int)($exp * 1000)) / 1000; // full jitter: 0..exp
}
for ($i = 0; $i < 5; $i++) {
printf("attempt %d -> wait %.3fs\n", $i, backoffDelay($i));
}Eine Retry-Schleife
Die einzelnen Bausteine zusammenführen: eine begrenzte Anzahl von Versuchen, Wiederholungen nur bei wiederholbaren Fehlern, zwischen den Versuchen mit Jitter und Backoff warten und den letzten Fehler weitergeben, wenn alle Versuche fehlschlagen.
<?php
function withRetry(callable $op, int $maxAttempts = 4): mixed {
$attempt = 0;
while (true) {
try {
return $op();
} catch (\Throwable $e) {
$attempt++;
if ($attempt >= $maxAttempts || !isRetryable($e)) {
throw $e; // give up
}
usleep((int)(backoffDelay($attempt) * 1_000_000));
}
}
}
function isRetryable(\Throwable $e): bool { return $e->getCode() === 0 || $e->getCode() >= 500; }
function backoffDelay(int $a): float { return min(5.0, 0.1 * (2 ** $a)) * (mt_rand(0, 100) / 100); }Der Circuit Breaker
Retries helfen bei kurzen Aussetzern, aber wenn eine Abhängigkeit wirklich ausgefallen ist, verschwendet es nur Zeit und Ressourcen, jede Anfrage zu wiederholen. Ein Circuit Breaker verfolgt Fehler und öffnet, sobald sie einen Schwellenwert überschreiten – er unterbricht Aufrufe direkt und schlägt sofort fehl, statt auf einen ausgefallenen Service zu warten.
Er hat drei Zustände: Closed (Aufrufe werden ausgeführt, Fehler gezählt), Open (Aufrufe werden sofort abgelehnt) und Half-Open (einige Testaufrufe prüfen die Erholung).
Zustandsautomat des Circuit Breakers
Die Übergänge: Closed → Open, wenn die Fehler den Schwellenwert überschreiten. Open → Half-Open nach einer Abkühlphase. Half-Open → Closed nach einer erfolgreichen Prüfung oder zurück zu Open bei einem Fehler. Der Zustand muss von den PHP-Prozessen gemeinsam genutzt werden (Redis/APCu), da jede Anfrage in einem neuen Prozess ausgeführt wird.
<?php
final class CircuitBreaker {
public function __construct(
private int $threshold = 5,
private int $coolDown = 30, // seconds
) {}
public function call(callable $op, array &$state): mixed {
if ($state['status'] === 'open') {
if (time() - $state['openedAt'] < $this->coolDown) {
throw new \RuntimeException('Circuit open - failing fast');
}
$state['status'] = 'half-open'; // time to probe
}
try {
$result = $op();
$state = ['status' => 'closed', 'failures' => 0]; // recovered
return $result;
} catch (\Throwable $e) {
$state['failures'] = ($state['failures'] ?? 0) + 1;
if ($state['failures'] >= $this->threshold || $state['status'] === 'half-open') {
$state['status'] = 'open';
$state['openedAt'] = time();
}
throw $e;
}
}
}Bulkheads
Das nach den Schotten eines Schiffs benannte Bulkhead-Muster isoliert Ressourcen, sodass ein Fehler in einem Bereich nicht das gesamte Schiff zum Sinken bringt. Wenn alle Ihre Worker den langsamen Reports-Service aufrufen können, kann ein Ausfall von Reports jeden Worker belegen und Checkout den Zugriff verwehren.
Teilen Sie Ressourcen auf – separate Verbindungspools, separate Worker-Pools oder Warteschlangen pro Abhängigkeit oder Begrenzungen der Nebenläufigkeit pro nachgelagertem Service –, sodass eine fehlerhafte Abhängigkeit nur ihren eigenen Anteil erschöpft.
Graceful Degradation & Fallbacks
Wenn eine nicht kritische Abhängigkeit nicht verfügbar ist, sollten Sie die Funktionalität reduzieren, statt einen Fehler zurückzugeben. Liefern Sie einen gecachten Wert, einen Standardwert oder eine eingeschränkte Funktionalität. Der offene Zustand des Circuit Breakers ist der natürliche Auslöser für den Fallback-Pfad.
<?php
function getRecommendations(callable $remoteCall, Redis $cache, string $userId): array {
try {
$recs = $remoteCall($userId);
$cache->setex("recs:$userId", 3600, json_encode($recs));
return $recs;
} catch (\Throwable $e) {
// Fallback 1: last-known-good from cache
if ($cached = $cache->get("recs:$userId")) {
return json_decode($cached, true);
}
// Fallback 2: generic popular items - never block the page
return ['popular-1', 'popular-2'];
}
}Idempotenzschlüssel für sichere Retries
Retries sind nur bei idempotenten Operationen sicher. Für eine nicht idempotente Aktion wie „Karte belasten“ fügen Sie einen Idempotenzschlüssel hinzu, den der Server zur Deduplizierung verwendet: Wenn ein Retry eintrifft, nachdem der erste Versuch bereits erfolgreich war, die Antwort aber verloren ging, gibt der Server das ursprüngliche Ergebnis zurück, statt die Karte zweimal zu belasten.
<?php
function chargeWithRetry(callable $http, string $orderId, int $cents): array {
// Same key across all retries of THIS logical charge
$key = 'charge-' . $orderId;
return withRetry(fn() => $http('POST', '/charges', [
'headers' => ['Idempotency-Key' => $key],
'json' => ['order' => $orderId, 'amount' => $cents],
]));
}
function withRetry(callable $op) { return $op(); } // see earlier sceneAlles zusammenführen
Die Muster lassen sich kombinieren, und die Reihenfolge ist wichtig. Ein robuster ausgehender Aufruf ist typischerweise so verschachtelt:
- Timeout bei jedem einzelnen Versuch (innerste Ebene).
- Retry mit Backoff um den Aufruf mit Timeout herum für vorübergehende Aussetzer.
- Circuit Breaker um den Retry herum, damit ein andauernder Ausfall schnell den Stromkreis öffnet.
- Bulkhead, der begrenzt, wie viel Kapazität diese Abhängigkeit verbrauchen darf.
- Fallback als äußerste Ebene, der alles abfängt, was nach außen gelangt.
Es gibt Wrapper nach dem Muster von Resilience4PHP, aber das Verständnis der Schichtung ist wichtiger als ein bestimmtes Paket.
Kurzprüfung
Das richtige Muster auswählen.
Zusammenfassung
Teilausfälle überstehen:
- Timeouts bei jedem Aufruf verhindern die Erschöpfung von Workern und kaskadierende Ausfälle.
- Retries nur bei idempotenten Operationen und wiederholbaren Fehlern, mit exponentiellem Backoff + Jitter.
- Circuit Breaker schlagen bei einer ausgefallenen Abhängigkeit schnell fehl (Closed → Open → Half-Open).
- Bulkheads isolieren Ressourcen, sodass ein Fehler nicht alle Ressourcen blockieren kann.
- Graceful Degradation / Fallbacks halten zentrale Abläufe am Leben.
Zusammengeschichtet verwandeln diese Muster unvermeidliche Fehler in begrenzte, behebbare Ereignisse.
Häufig gestellte Fragen
Ist die Lektion „Resilienz: Circuit Breaker und Retries“ kostenlos?
Ja — der vollständige Text von „Resilienz: Circuit Breaker und Retries“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des PHP Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der PHP Academy-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Resilienz: Circuit Breaker und Retries“?
Systeme auch bei Teilausfällen stabil halten Du übst PHP Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um PHP Academy zu starten?
Keine Vorkenntnisse erforderlich. PHP Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 4 von 4.
Wie lange dauert die Lektion „Resilienz: Circuit Breaker und Retries“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser PHP Academy-Lektion Code schreiben und ausführen?
Ja. Jede PHP Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- Vom Monolithen zu Microservices
- Servicekommunikation: REST und gRPC
- API-Gateways und Service Discovery
- Resilienz: Circuit Breaker und Retries