Circuito Breaker e degrado
Circuito Breaker (CB) è un pattern di protezione che interrompe le chiamate alla dipendenza degradata per localizzare il guasto e proteggere i servizi upstream e l'utente. Degrado (graceful degradation) - Semplifica consapevolmente la funzionalità in caso di carenza di risorse o guasti (ad esempio restituzione di dati nella cache/incompleti, disattivazione di file costosi) senza downtime completi.
L'obiettivo principale è quello di mantenere la SLO e l'esperienza utente con guasti controllati, invece di cadute a cascata.
1) Quando applicare
La dipendenza è instabile: crescita p95/p99, timeout, risposte sbagliate.
API esterne con limiti rigidi/penalti.
Backend pesanti (ricerche, referenze, rapporti) dove i retrai aumentano la tempesta.
Zone ad alta quota a rischio di esaurimento dei pool (composti, trad).
2) Stati CB e transizioni
Classico tre:1. Closed - traffico in corso, metriche di errore/latenza contano.
2. Open - Le chiamate vengono immediatamente rifiutate (fail-fast) e/o tradotte in fallback.
3. Half-Open - Un numero limitato di query di prova determina se chiudere l'interruttore.
Trigger di apertura
Soglia di errore/timeout per finestra (ad esempio, il 50% degli ultimi N).
Soglia di latenza (ad esempio p95> target).
Criteri combinati (errori) oltre il timeout.
Timeout (cool-down)
Fisso (ad esempio 10-60 secondi) o adattivo (aumento esponenziale in caso di ripetizioni).
3) Timeout, retrai e jitter
I timeout sono sempre più brevi di SLO upstream e coerenti per catena (deadline propagation).
Retrai solo per operazioni idipotenti; 1-2 tentativi sono sufficienti nella maggior parte dei casi.
Backoff + jitter (full jitter) impedisce le onde sincronizzate di ripetersi.
Hedging (query di riserva) è conveniente e solo per letture molto critiche.
4) Isolamento bulkhead e «fusibili»
Separare i pool di connessioni/worker/code per dominio e tipo di traffico (VIP, attività di sfondo, API pubbliche).
Caps a concorrency per operazioni «costose».
Admision control: guasto leggero prima che la coda si estenda.
5) Fallback e scenari di degrado
Opzioni
Cache/risposte stale: «stale-while-revalidate», restituzione dati dalla cache L2/L3.
Read-only - Blocco scrivere/comandi, consentire letture sicure.
Le risposte surrogate sono dati incompleti (ad esempio, senza raccomandazioni/avatar).
Disattivazione funzionale: nascondi temporaneamente widget/fici non critici.
Feature flags - Modifica rapida del comportamento senza rilascio.
Regole
Fallback deve essere determinata, veloce e sicura secondo i dati.
Contrassegnare chiaramente il percorso degradato nei cassetti/roulotte/metriche.
6) Priorità e traffico-shiping
I piani VIP/paganti sono una priorità/quota maggiore in caso di deficit.
Rate limits e throttling riducono il carico delle dipendenze degradate.
Shed load: riduzione della qualità (ad esempio, meno risultati, immagini tagliate) fino alla stabilizzazione.
7) Osservabilità e segnalazione
Metriche CB
Stato (closed/open/half-open) e durata dello stato.
Percentuale di guasti per motivi: CB-open, timeout, 5xx, retry-exhausted.
p95/p99 latitanza «prima» e «dopo» interruttore.
Numero di richieste tramite fallback.
Tracking
Annotazioni span: «circuito = opened», «fallback = cache», «admissione = denied».
Correlazione con limiti (429/RateLimit -), code e proiettili di connessione.
Logi/verifiche
Motivo di apertura/chiusura, soglie, identificatori di dipendenze.
8) Contratti e protocollo
HTTP
Fail-fast: «503 Service Unavailable» con «Retry-After» (o «429» a limiti).
Partial content/stale: «200 »/« 206» con metadati di degrado (ad esempio, «X-Degraded: true»).
Criteri cache: 'Cache-Control: stale-if-errore, stale-while-revalidate'.
gRPC
«UNAVAILABLE», «DEADLINE _ EXCEEDED», la semantica dei retrai nelle polizze client/proxy.
Deadline/timeout nel contesto della richiesta; La diffusione della deadline in fondo alla catena.
Idampotenza
Idempotency-Key per le operazioni POST, deduplicazione al confine.
9) Implementazione tipica (pseudocode)
pseudo onRequest(req):
if circuit. isOpen(dep):
return fallbackOrFail(req)
with timeout(T):
try:
resp = call(dep, req)
circuit. recordSuccess(dep, latency=resp. latency)
return resp except TimeoutError or 5xx as e:
circuit. recordFailure(dep)
if circuit. shouldOpen(dep):
circuit. open(dep, coolDown=adaptive())
return fallbackOrFail(req)
Prova Half-Open
pseudo onTimer():
if circuit. state(dep) == OPEN and coolDownExpired():
circuit. toHalfOpen(dep)
onRequestHalfOpen(req):
if circuit. allowTrial (dep): # e.g. 1 try: call -> success => close catch: reopen with longer coolDown else:
return fallbackOrFail(req)
10) Impostazione delle soglie
Finestra di osservazione: N scorrevole secondi/query.
Soglia di errore: 20-50% nella finestra (dipende dal profilo).
Soglia di latenza: p95 ≤ SLO target (ad esempio 300-500 ms); il superamento è considerato «errore» per CB.
Hot-down adattivo: 10s-30s-60s a ripetizione.
11) Test e pratiche di caos
Chaos: iniezione di latenza/errore a seconda, guasto DNS, drop pacchetti.
Game days: avvia «apri» l'interruttore in un ambiente boato, controlla fallback.
Canary: includere le regole di degrado St. Degrado prima per l' 1-5% del traffico.
Budget SLO - Consente gli esperimenti fino a esaurimento error-budget.
12) Integrazione con la multi-tenenza
Lo stato CB può essere memorizzato per-dipendency per-tenant (per gli affittuari rumorosi) o globalmente, a seconda del profilo di carico.
Dati fallback e cache segmentare in «tenant _ id».
Priorità/quote - secondo i piani (i VIP non devono subire il comportamento di Starter).
13) Foglio di assegno prima di vendere
- Timeout e deadline completi e coerenti.
- I retrai sono limitati, solo per operazioni idipotenti, con backoff + jitter.
- Le soglie CB sono giustificate dai dati del test di carico.
- I percorsi fallback esistono, veloci e sicuri; la cache dei criteri è definita.
- Isolamento bulkhead: pool/code/limiti separati.
- Metriche/trailer/logi segnano il degrado e lo stato di CB.
- Documentazione dei contratti di risposta (HTTP/gRPC) con esempi di titoli/codici.
- Script di caos e game-days si svolgono regolarmente; c'è il runbook.
14) Errori tipici
Non ci sono timeout di retrai e cadute a cascata.
Un unico CB globale anziché selettivo (con endpoint/metodo) è un rifiuto superfluo.
Un interruttore aperto senza fallback → gli schermi vuoti invece di un X degradato.
I Retrai senza Jitter hanno → una tempesta sincrona di richieste.
Duraturo-down in caso di guasti a breve termine o troppo breve in condizioni resistenti - flip-flop.
Assenza di bullkhead - Esaurimento dei pool condivisi e «head-of-line blocking».
15) Scelta rapida della strategia
Letture di grande importanza: CB + cache di risposte stale + hedging (economico).
Registrazioni/pagamenti: timeout rigoroso, minimi retrai, idempotency keys, assenza di fallback «sporco».
API esterne: CB con soglie aggressive, hot-down adattivo, throttling rigoroso.
Microservizi a carico pulsante: bulkheads, caps su concertency, priorità VIP.
Conclusione
Il circuito Breaker e il degrado gestito sono «assicurazioni» architettoniche, che trasformano i guasti caotici in comportamenti prevedibili. Timeout chiari, retrai limitati con jitter, pool isolati, percorsi fallback elaborati e telemetria rendono il sistema resistente ai guasti di dipendenza e mantengono lo SLO anche nei periodi di picco e di emergenza.