Circuit Breaker Pattern | Enjyn Gruppe
Hallo Welt
Hallo Welt
Original Lingva Deutsch
Übersetzung wird vorbereitet...
Dieser Vorgang kann bis zu 60 Sekunden dauern.
Diese Seite wird erstmalig übersetzt und dann für alle Besucher gespeichert.
0%
DE Zurück zu Deutsch
Übersetzung durch Lingva Translate

235 Dokumentationen verfügbar

Wissensdatenbank

Circuit Breaker Pattern

Zuletzt aktualisiert: 20.01.2026 um 11:24 Uhr

Circuit Breaker Pattern

Das Circuit Breaker Pattern verhindert Kaskadenausfälle in verteilten Systemen. Lernen Sie die States, Konfiguration und Implementierung für resiliente Anwendungen.

Das Problem

┌─────────────────────────────────────────────────────────────┐
│                 KASKADEN-AUSFALL                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   Service A                Service B              Service C │
│   ┌───────┐                ┌───────┐              ┌───────┐│
│   │       │──── Call ─────►│       │──── Call ───►│  💥   ││
│   │       │                │       │              │ DOWN  ││
│   │       │◄─── Timeout ───│       │◄─── Timeout ─│       ││
│   │       │                │       │              └───────┘│
│   │       │                │  ⏳   │                        │
│   │  ⏳   │                │ Wartet│                        │
│   │ Wartet│                │       │                        │
│   └───────┘                └───────┘                        │
│                                                             │
│   OHNE CIRCUIT BREAKER:                                    │
│   • Threads blockieren beim Warten                         │
│   • Timeouts addieren sich                                 │
│   • Ressourcen werden erschöpft                            │
│   • Ausfall propagiert sich nach oben                      │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Die Lösung: Circuit Breaker

┌─────────────────────────────────────────────────────────────┐
│                 CIRCUIT BREAKER STATES                      │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│              ┌─────────────────────────────┐               │
│              │                             │               │
│              ▼                             │               │
│       ┌────────────┐    Failure          │               │
│       │   CLOSED   │    Threshold         │               │
│       │            │    erreicht          │               │
│       │ (Normal)   │─────────────────┐    │               │
│       └────────────┘                 │    │               │
│              ▲                       │    │               │
│              │                       ▼    │               │
│         Success              ┌────────────┐               │
│         Threshold            │    OPEN    │               │
│         erreicht             │            │               │
│              │               │ (Blocked)  │               │
│       ┌────────────┐         └─────┬──────┘               │
│       │ HALF-OPEN  │◄──────────────┘                      │
│       │            │    Nach Timeout                       │
│       │ (Testing)  │                                       │
│       └─────┬──────┘                                       │
│             │                                              │
│             │ Failure                                      │
│             └──────────────────────────────►(zurück OPEN) │
│                                                             │
│   CLOSED:    Requests gehen durch                          │
│   OPEN:      Requests werden sofort abgelehnt (Fail Fast) │
│   HALF-OPEN: Testweise einige Requests durchlassen        │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Konfiguration

CIRCUIT BREAKER PARAMETER

┌────────────────────────┬────────────────────────────────────┐
│ failureThreshold       │ Anzahl Fehler bis OPEN (z.B. 5)   │
├────────────────────────┼────────────────────────────────────┤
│ failureRateThreshold   │ Fehler-% bis OPEN (z.B. 50%)      │
├────────────────────────┼────────────────────────────────────┤
│ successThreshold       │ Erfolge bis CLOSED (z.B. 3)       │
├────────────────────────┼────────────────────────────────────┤
│ timeout                │ Request Timeout (z.B. 3s)         │
├────────────────────────┼────────────────────────────────────┤
│ resetTimeout           │ Zeit bis HALF-OPEN (z.B. 30s)     │
├────────────────────────┼────────────────────────────────────┤
│ slidingWindowSize      │ Anzahl Requests für Berechnung    │
└────────────────────────┴────────────────────────────────────┘

Beispiel-Konfiguration:
• 5 Fehler in den letzten 10 Requests → OPEN
• 30 Sekunden warten → HALF-OPEN
• 3 erfolgreiche Requests in HALF-OPEN → CLOSED

JavaScript Implementation

// Einfache Circuit Breaker Klasse

class CircuitBreaker {
    constructor(options = {}) {
        this.failureThreshold = options.failureThreshold || 5;
        this.successThreshold = options.successThreshold || 3;
        this.resetTimeout = options.resetTimeout || 30000;

        this.state = 'CLOSED';
        this.failureCount = 0;
        this.successCount = 0;
        this.lastFailureTime = null;
    }

    async execute(fn) {
        if (this.state === 'OPEN') {
            // Prüfen ob resetTimeout abgelaufen
            if (Date.now() - this.lastFailureTime >= this.resetTimeout) {
                this.state = 'HALF_OPEN';
                console.log('Circuit Breaker: HALF_OPEN');
            } else {
                throw new CircuitBreakerOpenError('Circuit is OPEN');
            }
        }

        try {
            const result = await fn();
            this.onSuccess();
            return result;
        } catch (error) {
            this.onFailure();
            throw error;
        }
    }

    onSuccess() {
        if (this.state === 'HALF_OPEN') {
            this.successCount++;
            if (this.successCount >= this.successThreshold) {
                this.reset();
                console.log('Circuit Breaker: CLOSED');
            }
        } else {
            this.failureCount = 0;  // Reset bei Erfolg
        }
    }

    onFailure() {
        this.failureCount++;
        this.lastFailureTime = Date.now();

        if (this.state === 'HALF_OPEN') {
            this.state = 'OPEN';
            this.successCount = 0;
            console.log('Circuit Breaker: OPEN (from HALF_OPEN)');
        } else if (this.failureCount >= this.failureThreshold) {
            this.state = 'OPEN';
            console.log('Circuit Breaker: OPEN');
        }
    }

    reset() {
        this.state = 'CLOSED';
        this.failureCount = 0;
        this.successCount = 0;
        this.lastFailureTime = null;
    }

    getState() {
        return this.state;
    }
}

class CircuitBreakerOpenError extends Error {
    constructor(message) {
        super(message);
        this.name = 'CircuitBreakerOpenError';
    }
}
// Verwendung

const circuitBreaker = new CircuitBreaker({
    failureThreshold: 5,
    successThreshold: 3,
    resetTimeout: 30000
});

async function fetchUser(userId) {
    return circuitBreaker.execute(async () => {
        const response = await fetch(`http://user-service/users/${userId}`, {
            timeout: 3000
        });

        if (!response.ok) {
            throw new Error(`HTTP ${response.status}`);
        }

        return response.json();
    });
}

// Aufruf mit Fallback
async function getUserWithFallback(userId) {
    try {
        return await fetchUser(userId);
    } catch (error) {
        if (error instanceof CircuitBreakerOpenError) {
            console.log('Circuit open, using cached data');
            return getCachedUser(userId);
        }
        throw error;
    }
}

PHP Implementation mit Opossum

// Installation: composer require leocarmo/circuit-breaker-php

use LeoCarmo\CircuitBreaker\CircuitBreaker;

// Circuit Breaker mit Redis Storage
$circuitBreaker = new CircuitBreaker(
    new RedisAdapter($redis, 'user-service'),
    'user-service',
    [
        'timeWindow' => 60,           // Sliding Window (Sekunden)
        'failureRateThreshold' => 50, // 50% Fehlerrate
        'intervalToHalfOpen' => 30,   // Zeit bis HALF-OPEN (Sekunden)
        'minimumRequests' => 10,      // Min. Requests für Berechnung
        'successRateToClose' => 80,   // 80% Erfolg → CLOSED
    ]
);

// Verwendung
public function getUser(int $userId): ?User
{
    if (!$this->circuitBreaker->isAvailable()) {
        // Circuit ist OPEN - Fallback nutzen
        return $this->getCachedUser($userId);
    }

    try {
        $response = $this->httpClient->get("/users/{$userId}");
        $this->circuitBreaker->success();
        return User::fromResponse($response);
    } catch (Exception $e) {
        $this->circuitBreaker->failure();
        throw $e;
    }
}

Resilience4j (Java)

// build.gradle
implementation 'io.github.resilience4j:resilience4j-circuitbreaker:2.0.0'

// Java Configuration
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
    .failureRateThreshold(50)                     // 50% Fehlerrate
    .waitDurationInOpenState(Duration.ofSeconds(30))
    .permittedNumberOfCallsInHalfOpenState(3)
    .slidingWindowSize(10)
    .build();

CircuitBreakerRegistry registry = CircuitBreakerRegistry.of(config);
CircuitBreaker circuitBreaker = registry.circuitBreaker("userService");

// Verwendung
Supplier<User> decoratedSupplier = CircuitBreaker
    .decorateSupplier(circuitBreaker, () -> userService.getUser(userId));

Try.ofSupplier(decoratedSupplier)
    .recover(CircuitBreakerOpenException.class, e -> getCachedUser(userId))
    .get();

// Mit Annotations (Spring)
@CircuitBreaker(name = "userService", fallbackMethod = "getCachedUser")
public User getUser(Long userId) {
    return userServiceClient.getUser(userId);
}

public User getCachedUser(Long userId, Exception e) {
    return userCache.get(userId);
}

Polly (.NET)

// NuGet: Polly

// Circuit Breaker Policy
var circuitBreakerPolicy = Policy
    .Handle<HttpRequestException>()
    .Or<TimeoutException>()
    .CircuitBreakerAsync(
        exceptionsAllowedBeforeBreaking: 5,
        durationOfBreak: TimeSpan.FromSeconds(30),
        onBreak: (exception, timespan) => {
            Console.WriteLine($"Circuit opened for {timespan.Seconds}s");
        },
        onReset: () => {
            Console.WriteLine("Circuit closed");
        },
        onHalfOpen: () => {
            Console.WriteLine("Circuit half-open");
        }
    );

// Verwendung
try
{
    var result = await circuitBreakerPolicy.ExecuteAsync(
        async () => await httpClient.GetAsync("/api/users/1")
    );
}
catch (BrokenCircuitException)
{
    // Fallback
    return GetCachedUser(1);
}

// Advanced: Mit Timeout kombiniert
var policy = Policy.WrapAsync(
    Policy.TimeoutAsync(TimeSpan.FromSeconds(3)),
    circuitBreakerPolicy
);

Monitoring

// Circuit Breaker Metriken exportieren

const circuitBreakerMetrics = {
    state: 'closed',           // closed, open, half_open
    totalCalls: 1000,
    successfulCalls: 950,
    failedCalls: 50,
    notPermittedCalls: 0,      // Calls blocked by OPEN circuit
    failureRate: 5.0,          // %
    slowCallRate: 2.0,         // %
    timeInOpenState: 0,        // Sekunden
    lastStateChange: '2024-01-15T10:30:00Z'
};

// Prometheus Metriken
circuit_breaker_state{service="user-service"} 1  // 1=closed, 0=open
circuit_breaker_calls_total{service="user-service",result="success"} 950
circuit_breaker_calls_total{service="user-service",result="failure"} 50
circuit_breaker_failure_rate{service="user-service"} 5.0

// Alerting
ALERT CircuitBreakerOpen
  IF circuit_breaker_state == 0
  FOR 1m
  LABELS { severity = "warning" }
  ANNOTATIONS {
    summary = "Circuit breaker is OPEN",
    description = "Circuit breaker for {{ $labels.service }} is open"
  }

Best Practices

1. FALLBACK STRATEGIEN
   ┌────────────────────────────────────────────────────────┐
   │ • Cached Data zurückgeben                             │
   │ • Default Value zurückgeben                           │
   │ • Alternative Service anfragen                        │
   │ • Graceful Degradation (reduzierte Funktionalität)   │
   └────────────────────────────────────────────────────────┘

2. RICHTIGE SCHWELLWERTE
   ┌────────────────────────────────────────────────────────┐
   │ • Zu niedrig: Circuit öffnet zu früh                  │
   │ • Zu hoch: Schäden bevor Circuit öffnet              │
   │ • Sliding Window für stabilere Berechnung            │
   │ • Minimum Requests bevor Entscheidung                │
   └────────────────────────────────────────────────────────┘

3. KOMBINIEREN MIT ANDEREN PATTERNS
   ┌────────────────────────────────────────────────────────┐
   │ • Retry (innerhalb Circuit Breaker)                   │
   │ • Timeout (vor Circuit Breaker)                       │
   │ • Bulkhead (Ressourcen isolieren)                    │
   │ • Rate Limiting                                       │
   └────────────────────────────────────────────────────────┘

4. MONITORING UND ALERTING
   ┌────────────────────────────────────────────────────────┐
   │ • State-Änderungen loggen                             │
   │ • Metriken exportieren                                │
   │ • Alerts bei OPEN State                               │
   │ • Dashboard für Übersicht                             │
   └────────────────────────────────────────────────────────┘
💡 Zusammenfassung: 1. Circuit Breaker verhindert Kaskadenausfälle
2. Drei States: CLOSED → OPEN → HALF-OPEN
3. Immer Fallback-Strategie implementieren
4. Mit Timeout und Retry kombinieren
5. State-Änderungen monitoren und alerten

Weitere Informationen

Enjix Beta

Enjyn AI Agent

Hallo 👋 Ich bin Enjix — wie kann ich dir helfen?
120