Încercați din nou și politicile de backoff
Repetițiile (retries) ajută la supraviețuirea eșecurilor temporare, dar dacă sunt configurate incorect, ele provoacă avalanșe de trafic, duplicate ale operațiunilor și căderi în cascadă. O politică de retray fiabilă începe întotdeauna cu termene limită/termene limită, ia în considerare idempotența și utilizează backoff + jitter.
1) Principii de bază
1. Primul timeout/termen limită, apoi retragere. Repetarea fără limită de timp prelungește doar eșecul.
2. Retray - numai pentru operațiuni sigure/idempotente. Pentru cei nesiguri - prin chei de idempotenta si garantii de tranzactie.
3. Backoff-ul este obligatoriu. Exponențial sau GCRA-ca cu jitter pentru a desincroniza undele.
4. Limitați numărul de încercări și timpul bugetar total. Nu părăsiți SLO-ul utilizatorului.
5. Respectați semnalele de infrastructură. '429/503' + 'Retry-After', starea întrerupătorului, limitele cozii.
2) Termene și termene limită (propagare termen limită)
Solicitați timeout <SLO service, termenul limită se propagă în jos pe lanț (HTTP headers/gRPC context).
Compoziția Timeout: total (prima încercare + backoff + ulterioară) ≤ termenul limită de utilizare.
Diferite intervale de timp pentru citiri/înregistrări: înregistrările sunt mai scurte și mai stricte; citirile permit acoperirea.
3) Idempotența și repetările sigure
Citește (GET/idempotent RPC): repetat în siguranță cu '5xx', 'INDISPONIBIL', timeout-uri de rețea.
Înregistrări:- Utilizați „Idempotency-Key” (HTTP) sau solicitați-ID pe frontieră; serverul trebuie să deduplicate.
- Scrieți handleri idempotenți: „upsert”, „cel puțin o dată” + compensație (saga).
- Plăți/decontări externe - numai cu chei idempotente și jurnal de tranzacții.
4) Algoritmi de backoff
Exponențial: 'base 2 ^ încercare', delimitat de 'max _ backoff'.
Jitter decorate (Jitter complet/egal) - aleatoriu în gama pentru a desincroniza clienții.
Întârzieri GCRA/Token-Bucket: în concordanță cu limitele de rată.
Frontiere: 'initial _ backoff' (50-200 ms citește; 200-500 ms records), 'max _ backoff' (1-5 s), 'max _ elapsed' (de exemplu, 3-10 s).
Modelul recomandat este backoff exponențial + jitter complet.
5) Repetați/nu repetați politicile de decizie
Repetăm la:- Erori de rețea/timeout-uri, '429' (cu respect 'Retry-After'), 'soft' 5xx' ('502/503/504'), gRPC 'INDISPONIBIL/DEADLINE _ DEPĂȘIT'.
- „4xx” (cu excepția „409/429/408” în unele scenarii), erori de afaceri, „401/403”, erori de validare, steagul „DoNotRetry” explicit.
- „409 Conflict” - uneori repetat cu o întârziere după consens/încuietori.
- '404' pentru lecturi permanent consistente - una sau două ori retray cu un mic backoff.
6) capace de concurență și „furtună retray”
Limitați retroadele simultane per client/per chiriaș/per punct final.
Limita totală a încercărilor per cerere (ex. 2-3).
Încetiniți punctele finale fierbinți prin controlul admiterii, pentru a nu umfla cozile.
7) Interacțiunea cu întrerupătorul de circuit și limitele
Dacă CB este deschis, nu efectuați retroactive direct - mergeți la rezervă sau așteptați eșantioane „pe jumătate deschise”.
La „429” - respect „Retry-After”; dacă nu, utilizați „moale” backoff.
Retraiele pot crește tulpina; aplicați praguri adaptive (mai mici „max _ încercări” pentru un incident).
8) Protocoale și contracte
HTTP
Coduri: '408/429/5xx'.
Anteturi: 'Retry-After', familia 'RateLimit-', 'Idempotency-Key', 'Request-Id'.
Clientul trebuie să trimită 'X-Request-Timeout '/' Deadline-At' (dacă da).
gRPC
Utilizați contextul cu un termen limită; respectă „INDISPONIBIL”, „DEADLINE _ EXCEED”, politicile de retractare pe metodă.
Pentru RPC-urile idempotente, includeți retroactive; pentru mutații - numai cu suport idempotență.
9) Cozi, sarcini de fundal și integrări
Cel puțin o dată manipulanți → acțiuni idempotente, eliminare a duplicatelor cheie.
Întârziere coadă pentru backoff între încercări (de exemplu, 5s/30s/2m).
Coadă de litere moarte (DLQ) cu o limită de încercări și procesare manuală.
Outbox/CDC - astfel încât reluările să nu compromită integritatea tranzacțională.
10) Gard vs Retries
Acoperirea este utilă pentru citirile extrem de critice în latența cozii.
Limită: nu mai mult de X% din cereri, întârziere start-grace (de exemplu, latență p95), anularea pierderilor.
Nu aplicați acoperirea pentru a scrie operațiuni fără idempotență puternică.
11) Telemetrie și observabilitate
Теги: 'chiriaş _ id',' endpoint ',' încercare ',' decizie '(încercare/sărire),' motiv ',' backoff _ ms', 'deadline _ ms',' idempotency _ key '.
Valori: cota de retrageri, succesul după retrageri, p95/p99 "end-to-end', numărul de termene limită depășite, declanșarea CB.
Jurnale de audit: tastele/punctele finale „zgomotoase” superioare N, corelație cu 429/503.
12) Testarea și haosul
Profiluri: „ferăstrău” (izbucnire), „furtună” (timeout-uri de masă), erori „lipicioase” (fiecare Nth), cozi de latență.
Torus limitator/cache/coadă eșecuri, ceas-înclinare.
Verifică dacă durata totală (încercări + backoff) se încadrează în SLO.
13) Pseudocodul politicii
pseudo handle(req, deadline):
attempt = 0 backoff = initial()
while attempt < MAX_ATTEMPTS and now() < deadline:
attempt += 1 with timeout(per_attempt_timeout(deadline, attempt)):
try:
resp = call(req)
if isRetryableStatus(resp): raise Retryable(resp. status)
return resp except Retryable as e:
if circuit. isOpen(dep) or! isIdempotent(req): break sleep(jitter(backoff))
backoff = min(exp(backoff), MAX_BACKOFF)
except NonRetryable:
break return fail_or_fallback(req)
14) Șablon de configurare (exemplu)
yaml retries:
default:
max_attempts: 3 initial_backoff_ms: 150 max_backoff_ms: 2000 strategy: exponential_full_jitter respect_retry_after: true per_attempt_timeout_fraction: 0. 4 # 40% of remaining deadline hedging:
enabled: false read_heavy:
max_attempts: 4 initial_backoff_ms: 80 max_backoff_ms: 1200 hedging:
enabled: true start_after_p95_ms: 300 max_extra_requests_ratio: 0. 05 write_strict:
max_attempts: 2 initial_backoff_ms: 250 max_backoff_ms: 1000 idempotency_required: true
limits:
concurrent_retries_per_tenant: 100 concurrent_retries_per_endpoint: 20
15) Lista de verificare pre-vânzare
- Termenele limită se propagă prin apeluri; durata totală a ≤ SLO.
- Algoritm de backoff cu jitter; parametrii validați prin încercarea de sarcină.
- IDempotence: chei/jurnale/compensații pentru înregistrări.
- Politicile de retractare diferă pentru citiri și înregistrări; respect „Retry-After”.
- Retrage competitivitatea și numărul total de încercări sunt limitate.
- Integrarea cu întrerupător de circuit și limitele de rată este configurată.
- Telemetrie: etichete, valori, jurnalele de motive; tablouri de bord p95/p99, cota de succes după retroys.
- Teste de „furtuni” și cozi de latență, DLQ pentru sarcini.
- Documentația clientului: coduri/titluri, backoff și exemple de anulare.
16) Erori tipice
Reluările fără termene limită sunt „așteptări eterne”.
Pauze fixe fără jitter - unde sincrone și autosabotaj DDoS.
Retraiele de înregistrări nesigure fără idempotență - duplicate și desincronizare.
Ignorarea semnalelor „Retry-After” și CB - incident escaladarea.
Blocaje în cozi din cauza lipsei de plafoane și a controlului admiterii.
Lipsa de telemetrie a motivelor/soluțiilor de retroave - „zbor orb”.
17) Rețete rapide
Public API citește: 3 încercări, 'initial = 100ms',' max = 1s ', jitter complet, acoperirea a până la 5% din trafic.
Înregistrări critice (plată): 1-2 încercări maxime, timeout strict, obligatoriu „Idempotency-Key”, fără acoperire.
Integrări externe: respectați '429/Retry-After', 'max _ încercări = 3', 'max _ backoff = 2-5s', limite de flux de ieșire.
Sarcini de fundal: întârziere-backoff (5s → 30s → 2m), DLQ, handlers idempotent.
Concluzie
O bună politică de repetiție este un echilibru între recuperarea rapidă și eșecul controlat. Termenele limită, idempotența, backoff-ul exponențial cu jitter, limitarea concurenței și respectarea semnalelor de infrastructură transformă retraiele dintr-o „furtună” într-un instrument pentru îmbunătățirea fiabilității și a retenției SLO.