DevOps30 décembre 2025 11 min de lecture

Monitoring du Pattern Circuit Breaker : Guide Complet

Surveillez efficacement vos circuit breakers pour des microservices résilients. Métriques d'état, alertes et optimisation des seuils pour une haute disponibilité.

WizStatus Team
Auteur

Le pattern Circuit Breaker constitue l'un des mécanismes de résilience les plus importants dans les architectures microservices. Inspiré des disjoncteurs électriques, il protège les services des défaillances en cascade.

Mais un circuit breaker est efficace uniquement s'il est correctement configuré et surveillé.

Qu'est-ce que le Pattern Circuit Breaker ?

Le Circuit Breaker encapsule les appels vers des services externes et surveille leurs échecs. Il fonctionne selon trois états distincts.

Les trois états

              Échecs < seuil
         ┌───────────────────────┐
         │                       │
         ▼         Échec         │
    ┌─────────┐  ──────────►  ┌─────────┐
    │ CLOSED  │               │  OPEN   │
    │ (Normal)│  ◄──────────  │ (Fail)  │
    └─────────┘    Timeout    └─────────┘
         │                       │
         │                       │ Timeout
         │                       ▼
         │                 ┌───────────┐
         │                 │HALF-OPEN  │
         │  Succès test    │  (Test)   │
         └─────────────────┴───────────┘

État Closed (Normal)

Le fonctionnement normal :

# Pseudo-code circuit breaker
class CircuitBreaker:
    def __init__(self, failure_threshold=5, timeout=30):
        self.state = "CLOSED"
        self.failure_count = 0
        self.failure_threshold = failure_threshold
        self.timeout = timeout

    def call(self, func):
        if self.state == "CLOSED":
            try:
                result = func()
                self.failure_count = 0  # Reset on success
                return result
            except Exception as e:
                self.failure_count += 1
                if self.failure_count >= self.failure_threshold:
                    self.state = "OPEN"
                    self.opened_at = time.now()
                raise e

État Open (Protection)

Le circuit refuse les requêtes :

def call(self, func):
    if self.state == "OPEN":
        if time.now() - self.opened_at > self.timeout:
            self.state = "HALF-OPEN"
        else:
            raise CircuitOpenError("Circuit is open")

État Half-Open (Test)

Quelques requêtes de test passent :

def call(self, func):
    if self.state == "HALF-OPEN":
        try:
            result = func()
            self.state = "CLOSED"  # Recovery !
            self.failure_count = 0
            return result
        except Exception:
            self.state = "OPEN"  # Still failing
            self.opened_at = time.now()
            raise

Bénéfices du pattern

Le circuit breaker offre plusieurs avantages :

  • Fail-fast : Pas d'attente sur un service défaillant
  • Protection des ressources : Évite l'accumulation de connexions
  • Temps de récupération : Le service cible n'est pas submergé
Les implémentations populaires incluent Resilience4j (Java), Polly (.NET), et les fonctionnalités natives d'Istio.

Pourquoi Monitorer les Circuit Breakers

Le monitoring transforme les circuit breakers en outil d'observabilité proactive.

Détection des dépendances dégradées

Un circuit qui s'ouvre signale un problème :

# Exemple d'événement
event:
  type: circuit_breaker_opened
  circuit: payment-service
  timestamp: 2025-12-30T10:30:00Z
  failure_count: 5
  last_error: "Connection timeout"

Cette information est souvent disponible avant les alertes directes sur le service cible.

Validation des seuils

Le monitoring révèle si les seuils sont appropriés :

SituationSymptômeAction
Trop sensibleOuvertures fréquentesAugmenter failure_threshold
Trop laxisteJamais d'ouvertureRéduire failure_threshold
Timeout courtRejets inutilesAugmenter timeout
Timeout longLenteur de récupérationRéduire timeout

Impact utilisateur quantifié

Mesurez l'impact des circuits ouverts :

# Métriques d'impact
impact_metrics = {
    "circuit": "payment-service",
    "open_duration_seconds": 120,
    "requests_rejected": 1500,
    "estimated_revenue_lost": 15000,  # Calcul business
    "users_affected": 500
}

Identification des dépendances fragiles

Un circuit qui s'ouvre fréquemment signale une dépendance instable :

# Top 5 des circuits les plus problématiques
topk(5,
  increase(circuit_breaker_state_changes{to="open"}[7d])
)

Comment Monitorer les Circuit Breakers

Métriques d'état

Exposez l'état actuel de chaque circuit :

from prometheus_client import Gauge, Counter

# État actuel (0=closed, 1=half-open, 2=open)
circuit_state = Gauge(
    'circuit_breaker_state',
    'Current state of circuit breaker',
    ['circuit_name']
)

# Compteurs de transitions
state_transitions = Counter(
    'circuit_breaker_state_transitions_total',
    'Circuit breaker state transitions',
    ['circuit_name', 'from_state', 'to_state']
)

# Exemple d'usage
circuit_state.labels(circuit_name='payment-service').set(2)  # OPEN
state_transitions.labels(
    circuit_name='payment-service',
    from_state='closed',
    to_state='open'
).inc()

Métriques de requêtes

Distinguez les types de réponses :

# Compteur par type de résultat
circuit_calls = Counter(
    'circuit_breaker_calls_total',
    'Circuit breaker calls',
    ['circuit_name', 'result']  # success, failure, rejected
)

# Latence des appels réussis
circuit_latency = Histogram(
    'circuit_breaker_call_duration_seconds',
    'Call duration through circuit breaker',
    ['circuit_name'],
    buckets=[0.01, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10]
)

Intégration Resilience4j

Resilience4j expose des métriques Micrometer :

// Configuration avec métriques
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
    .failureRateThreshold(50)
    .waitDurationInOpenState(Duration.ofSeconds(30))
    .slidingWindowSize(10)
    .build();

CircuitBreaker circuitBreaker = CircuitBreaker.of("payment", config);

// Enregistrement des métriques
TaggedCircuitBreakerMetrics
    .ofCircuitBreakerRegistry(circuitBreakerRegistry)
    .bindTo(meterRegistry);

Métriques exposées automatiquement :

# État du circuit
resilience4j_circuitbreaker_state{name="payment"}

# Taux d'échec
resilience4j_circuitbreaker_failure_rate{name="payment"}

# Appels par type
resilience4j_circuitbreaker_calls_total{name="payment", kind="successful"}
resilience4j_circuitbreaker_calls_total{name="payment", kind="failed"}
resilience4j_circuitbreaker_calls_total{name="payment", kind="not_permitted"}

Dashboard de monitoring

Créez un dashboard dédié :

# Grafana dashboard panels
panels:
  - title: "Circuit States Overview"
    type: stat
    query: circuit_breaker_state

  - title: "Open Circuits"
    type: table
    query: circuit_breaker_state == 2

  - title: "State Transitions (24h)"
    type: timeseries
    query: increase(circuit_breaker_state_transitions_total[1h])

  - title: "Rejection Rate"
    type: gauge
    query: |
      rate(circuit_breaker_calls_total{result="rejected"}[5m])
      / rate(circuit_breaker_calls_total[5m])

  - title: "Top Problematic Circuits"
    type: table
    query: topk(10, increase(circuit_breaker_state_transitions_total{to="open"}[24h]))

Alertes intelligentes

Configurez des alertes graduées :

groups:
  - name: circuit_breaker_alerts
    rules:
      # Alerte informative : ouverture de circuit
      - alert: CircuitBreakerOpened
        expr: circuit_breaker_state == 2
        for: 0m
        labels:
          severity: info
        annotations:
          summary: "Circuit {{ $labels.circuit_name }} is open"

      # Alerte warning : circuit ouvert > 5 minutes
      - alert: CircuitBreakerOpenProlonged
        expr: circuit_breaker_state == 2
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Circuit {{ $labels.circuit_name }} open for 5+ minutes"

      # Alerte critique : circuit critique ouvert
      - alert: CriticalCircuitOpen
        expr: circuit_breaker_state{circuit_name=~"payment.*|order.*"} == 2
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "Critical circuit {{ $labels.circuit_name }} is open"

      # Alerte sur pattern : ouvertures fréquentes
      - alert: CircuitBreakerFlapping
        expr: increase(circuit_breaker_state_transitions_total{to="open"}[1h]) > 5
        labels:
          severity: warning
        annotations:
          summary: "Circuit {{ $labels.circuit_name }} opened 5+ times in 1 hour"

Bonnes Pratiques de Monitoring Circuit Breaker

Nommage descriptif

Nommez clairement vos circuits :

# Bon : descriptif
circuit_breaker(name="payment-service-charge")
circuit_breaker(name="inventory-service-reserve")

# Mauvais : générique
circuit_breaker(name="cb-1")
circuit_breaker(name="external-call")
Incluez le service appelant et le service cible dans le nom. Un nom comme order-to-payment-charge est immédiatement compréhensible.

SLO pour les circuits

Définissez des objectifs mesurables :

slos:
  - circuit: payment-service
    max_open_time_per_month: "0.1%"  # ~43 minutes
    max_openings_per_day: 2

  - circuit: inventory-service
    max_open_time_per_month: "0.5%"  # ~3.6 heures
    max_openings_per_day: 5

Corrélation avec incidents

Reliez les événements de circuit aux incidents :

def on_circuit_open(circuit_name, error):
    # Log structuré
    logger.warning("Circuit opened", extra={
        "circuit": circuit_name,
        "error": str(error),
        "downstream_service": extract_service(circuit_name)
    })

    # Création d'incident automatique si circuit critique
    if is_critical_circuit(circuit_name):
        incident_manager.create_incident(
            title=f"Circuit {circuit_name} opened",
            severity="high",
            tags=["circuit-breaker", circuit_name]
        )

Test avec chaos engineering

Testez régulièrement le comportement :

# Test avec injection de panne
def test_circuit_breaker_opens_on_failures():
    circuit = CircuitBreaker(failure_threshold=3)

    # Simuler des échecs
    with mock_service_failure():
        for _ in range(3):
            with pytest.raises(ServiceError):
                circuit.call(external_service.call)

    # Vérifier que le circuit s'est ouvert
    assert circuit.state == "OPEN"

    # Vérifier que les appels sont rejetés
    with pytest.raises(CircuitOpenError):
        circuit.call(external_service.call)

Documentation des seuils

Documentez chaque configuration :

# circuit-breaker-config.yaml
circuits:
  payment-service:
    failure_threshold: 5
    timeout_seconds: 30
    rationale: |
      - 5 échecs consécutifs car le service de paiement est critique
      - Timeout de 30s car les pics de charge durent généralement < 20s
      - Revu le 2025-12-01 après incident INC-456

  inventory-service:
    failure_threshold: 10
    timeout_seconds: 60
    rationale: |
      - 10 échecs car le service a des latences variables normales
      - Timeout de 60s car la récupération est lente
      - Revu le 2025-11-15

Conclusion

Le monitoring des circuit breakers transforme ce pattern de résilience en outil d'observabilité proactive.

Les bénéfices du monitoring :

  • Détection précoce des problèmes de dépendances
  • Validation et optimisation des seuils
  • Quantification de l'impact utilisateur
  • Guide pour l'amélioration de la résilience

Cette observabilité guide l'optimisation continue de votre architecture.

WizStatus surveille la disponibilité de vos services et dépendances externes, complémentant la protection de vos circuit breakers par une détection précoce des dégradations.

Articles connexes

Monitoring API : Bonnes Pratiques et Stratégies 2026
Monitoring

Monitoring API : Bonnes Pratiques et Stratégies 2026

Maîtrisez le monitoring de vos APIs avec les meilleures pratiques 2025. Métriques essentielles, alertes intelligentes et observabilité pour des APIs performantes.
18 min de lecture
Monitoring du Rate Limiting API : Métriques et Alertes
Monitoring

Monitoring du Rate Limiting API : Métriques et Alertes

Surveillez efficacement votre rate limiting API. Détection des abus, optimisation des quotas et préservation de l'expérience utilisateur légitime.
9 min de lecture
Optimisation du Temps de Réponse API : Techniques et Stratégies
Bonnes Pratiques

Optimisation du Temps de Réponse API : Techniques et Stratégies

Optimisez les performances de vos APIs avec des techniques éprouvées. Caching, async, compression et bonnes pratiques pour des temps de réponse minimaux.
13 min de lecture

Commencez à surveiller votre infrastructure dès aujourd'hui

Mettez ces conseils en pratique avec le monitoring WizStatus.

Essayer WizStatus Gratuitement