GH GambleHub

Circuito Breaker e Retrai

Circuito Breaker e Retrai

1) Perché è necessario

Le reti sono inaffidabili: la latitanza pulisce, i nodi calano e i limiti vengono raggiunti. I retrai vengono salvati da guasti a breve termine, mentre il Circuito Breaker protegge il sistema da guasti a cascata e da «sen-DDoS». La combinazione con i timeout e i limiti corretti conserva lo SLO, stabilizza i ritardi di coda e il prezzo del device.

2) Principi di base

Prima i timeout, poi i retrai, poi il Circuito Breaker.
Retraim solo operazioni Idempotent (GET, POST/PUT sicuri con chiave Idempotente).
Assegnare il budget dei retrai al 10-15% dell'RPS originale per il percorso.
Localizza il rifiuto: bullkhead (pool/quote separate) + rate-limit.
In caso di degrado - guasto rapido (fail-fast), graceful-degradation/stub.

3) Semantica dei retrai

Quando ritrarre

Errori transitori timeouts, 5xx, indisponibilità di rete, 429 (dopo «Retry-After»).
Impossibile ritrattare: errori aziendali evidenti (4xx ≠ 429), side-effect senza idemotia (pagamento senza chiave).

Strategie

Exponential backoff + jitter (completo o uniforme) - Alleggerisce i greggi di retrai.
Max attemps: 1-2 (raramente 3) - più dannoso.
Budget - Contatore globale di retrai/s per il servizio e per-sollest «retry tokens».
Hedging (raramente): ripresa parallela dopo t-quantili (p95) - solo per letture rigorosamente idipotenti.

Pseudocode backoff + jitter:
python base = 100 # ms for attempt in range(1, max_attempts+1):
try:
return call()
except Transient as e:
if attempt == max_attempts: raise sleep_ms = min(cap_ms, base 2(attempt-1))
sleep(random(0, sleep_ms)) # full jitter

4) Timeout e «guasto rapido»

Client timeout <upstream timeout: per non risparmiare richieste «zombie».
Делите: connect timeout, read timeout, overall deadline.
Timeout Tail-aware: mirare al p95/p99 + piccola scorta.
Utilizzare un campo di deadline condiviso (ad esempio, «deadline») e sfondarlo nella catena.

5) Circuito Breaker: come funziona

Stati:
  • Closed: salta il traffico, conta errori/latitanza.
  • Open: annulla immediatamente (o risposta di riserva).
  • Half-Open: richieste di verifica; Con il successo, si chiude.
Soglia di apertura:
  • Gli errori/timeout superano la quota X% per la finestra N query/secondi o p99 sopra la soglia.
  • Le statistiche scorrevole e il volume minimo (ad esempio, 50 query) sono rilevanti.

6) Bulkhead, quote e «dividi e regni»

Pool separati per-upstream e per-fic.
Quote di query in-flight No, no, no, no, no.
In caso di carenza, degrado il Fic a bassa priorità (feature flags).

7) Integrazione con il perimetro (Avvoy/Istio/Nginx)

Invoy (retry + outlier + CB, idea):
yaml routes:
- match: { prefix: "/api" }
route:
cluster: upstream_api timeout: 2s retry_policy:
retry_on: "connect-failure,reset,retriable-4xx,5xx"
num_retries: 2 per_try_timeout: 600ms retry_back_off: { base_interval: 100ms, max_interval: 800ms }
hedge_policy:
hedge_on_per_try_timeout: true initial_requests: 1 additional_request_chance: { numerator: 5, denominator: HUNDRED } # 5%
clusters:
- name: upstream_api circuit_breakers:
thresholds:
- priority: DEFAULT max_connections: 500 max_requests: 1000 max_retries: 200 outlier_detection:
consecutive_5xx: 5 interval: 5s base_ejection_time: 30s max_ejection_percent: 50
Istio (VirtualService fault/retry, esempio compresso):
yaml apiVersion: networking. istio. io/v1beta1 kind: VirtualService spec:
hosts: ["payments"]
http:
- route: [{ destination: { host: payments } }]
timeout: 2s retries:
attempts: 2 perTryTimeout: 600ms retryOn: "5xx,connect-failure,refused-stream,reset"
Nginx Ingress (annotazioni):
yaml nginx. ingress. kubernetes. io/proxy-connect-timeout: "2"
nginx. ingress. kubernetes. io/proxy-read-timeout: "2"
nginx. ingress. kubernetes. io/proxy-next-upstream: "error timeout http_502 http_503 http_504"
nginx. ingress. kubernetes. io/proxy-next-upstream-tries: "2"

8) Librerie e codice (stack snippet)

Java (Resilience4j):
java var cb = CircuitBreaker. ofDefaults("psp");
var retry = Retry. of("psp-retry",
RetryConfig. custom()
.maxAttempts(2)
.waitDuration(Duration. ofMillis(200))
.intervalFunction(IntervalFunction. ofExponentialRandomBackoff(100, 2. 0, 0. 5) )//jitter
.retryExceptions(SocketTimeoutException. class, IOException. class)
.build());

Supplier<Response> decorated =
CircuitBreaker. decorateSupplier(cb,
Retry. decorateSupplier(retry, () -> client. call()));

return Try. ofSupplier(decorated)
.recover(BusinessException. class, fallback())
.get();
Go (context deadline + backoff):
go ctx, cancel:= context. WithTimeout(context. Background(), 2time. Second)
defer cancel()
var lastErr error for i:= 0; i < 2; i++ {
reqCtx, stop:= context. WithTimeout(ctx, 600time. Millisecond)
lastErr = call(reqCtx)
stop()
if lastErr == nil { break }
sleep:= time. Duration(rand. Intn(1<<uint(7+i))) time. Millisecond // full jitter time. Sleep(min(sleep, 800time. Millisecond))
}
if lastErr!= nil { return fastFail() }
Node. js (got + p-retry):
js import pRetry from 'p-retry';
await pRetry(() => got(url, { timeout: { connect: 500, request: 2000 } }), {
retries: 2,
factor: 2,
randomize: true,
minTimeout: 100,
maxTimeout: 800,
onFailedAttempt: e => { if (isBusiness(e)) throw e; }
});

9) Bilancio dei retrai e SLO

Inserisci retry tokens: ogni retrai spende un token; il pool è limitato.
Collegare a error-budget: quando il burn-rate è sopra la soglia - disattivare i retrai, aprire il CB più spesso, attivare il degrado.
Rilasci canari: nei canari ridurre i tentativi e i token.

10) Hedging (attenzione)

Eseguire una richiesta aggiuntiva dopo la deadline, annullando il perdente.
Solo per le letture e le operazioni idropotenti «sicure»; limitare la quota (≤ 1-5%).
Tieni d'occhio l'aumento del carico di lavoro dell'upstream.

11) Osservabilità

Le metriche RED su rotte sono Rate, Errore, Duration (p50/p95/p99).
Metriche CB - Stato (open/half-open), frequenza di aperture, query saltate/fallite.
Retrai: attemps/sollest, retry-rate, token bruciati.
Perimetro: outlier-ejection, ejection-rate.
Tracciati: annotare «retry _ attempt», «cb _ state», «hedged = true», aprire «trace _ id».

12) Integrazione con l'architettura

Bullkhead + CB per ogni upstream critico.
Code/asincrone, per lunghe operazioni al posto di timeout folli.
Kash/stub - Per i file non critici a fail-open.
Se non si compensano i brutti retrai, si fermi la tempesta.

13) Anti-pattern

I retrai senza timeout → i connettori che dipendono e l'esaurimento dei pool.
Ripetizione di operazioni non idonee (doppi prelievi).
Una crescita esponenziale infinita senza cap e senza jitter.
Un unico CB su tutti gli upstream consente di trascinare un guasto su tutto il prodotto.
Ignora 429/' Retry-After '.
Il timeout del cliente è più lungo dell'upstream (o no).
«Trattare» gli errori aziendali con i retrai.

14) Assegno foglio di implementazione (0-30 giorni)

0-7 giorni

Definire le rotte e la loro idimpotenza.
Impostare i timeout (connect/read/overall), includere i retrai minimi (x 1) e CB di default.
Separare i pool/quote (bulkhead) per gli upstream principali.

8-20 giorni

Includere il jitter e il budget globale dei retrai, gli alert su retry-rate.
Configurare outlier-ejection sul perimetro, guasto rapido per il file low-prio.
Dashboard RED + CB/Retry, trailer con etichette.

21-30 giorni

Profili canarini retrae (meno tentativi), game-day «upstream lento/flaped».
Documentare la politica: chi/cosa ritrae, limiti, eccezioni.
Rivedere p95/p99 e timeout in base ai dati, non all'occhio.

15) Metriche di maturità

Il 100% delle rotte ha timeout e una politica di retrai/SAN documentata.
Retry-rate è incluso nel budget (10-15%), nessun picco in caso di incidenti.
I CB si attivano prima che l'intero pool crolli; Nessun guasto a cascata.
Le roulotte mostrano tentativi/hedging; p99 è stabile ai picchi.
Le release canarie usano un profilo «attento» dei retrai.

16) Brevi esempi di configurazione

Resilience4j YAML (Spring Boot, идея):
yaml resilience4j:
circuitbreaker:
instances:
psp:
slidingWindowType: COUNT_BASED slidingWindowSize: 100 minimumNumberOfCalls: 50 failureRateThreshold: 50 waitDurationInOpenState: 30s permittedNumberOfCallsInHalfOpenState: 5 retry:
instances:
psp:
maxAttempts: 2 waitDuration: 200ms enableExponentialBackoff: true exponentialBackoffMultiplier: 2. 0 retryExceptions:
- java. net. SocketTimeoutException
- java. io. IOException
Invoy rate-limit (frammento di idea):
yaml rate_limits:
- actions:
- generic_key: { descriptor_value: "api. payments" }

17) Conclusione

La resilienza è una disciplina: timeout del retrae (con jitter e budget) del Circuito Breaker + bulkhead/quote e revoca rapida. Regolare il perimetro (outlier-ejection), appendere i dashboard RED/CB/Retry, fissare la politica di idempotenza e tenere presente la SLI aziendale. Allora i guasti non saranno visibili e i veri incidenti non si trasformeranno in cadute a cascata.

Contact

Mettiti in contatto

Scrivici per qualsiasi domanda o richiesta di supporto.Siamo sempre pronti ad aiutarti!

Telegram
@Gamble_GC
Avvia integrazione

L’Email è obbligatoria. Telegram o WhatsApp — opzionali.

Il tuo nome opzionale
Email opzionale
Oggetto opzionale
Messaggio opzionale
Telegram opzionale
@
Se indichi Telegram — ti risponderemo anche lì, oltre che via Email.
WhatsApp opzionale
Formato: +prefisso internazionale e numero (ad es. +39XXXXXXXXX).

Cliccando sul pulsante, acconsenti al trattamento dei dati.