Testarea stabilității
1) Concepte și obiective de bază
Fiabilitate - probabilitatea de performanță; reziliență-comportamentul în timpul și după un eșec.
SLO/buget eronat: criterii de „acceptabilitate” a degradării.
Ipoteza stării de echilibru: așteptarea formală a măsurătorilor stabile (de ex. p95 <200 ms, rata de eroare <0. 5%). Experimentul este considerat de succes dacă ipoteza este susținută.
Tipuri de defecțiuni: rețea (latență, pierdere/duplicate, pauze), computațională (CPU, memorie), stocare (I/O, epuizare pe disc), dependențe (5xx, timeout, rate-limit), logică (incidente parțiale, „degradare lentă”), operațională (eliberare, configurare), „întunecat” creier, schimburi de oră).
2) Piramida sustenabilității
1. Încercări unitare de defecțiuni logice (retroys, idempotency, timeout).
2. Adaptoare componente cu injecție de eroare (Testcontainere/tc-netem).
3. Integrare/sistem cu rețea/bază de date/cache și profile din lumea reală.
4. Haos experimente în pre-prod (și apoi limitat în prod) pe runbooks.
5. Ziua jocului - exerciții de scenariu ale echipei (oameni + instrumente).
3) Observabilitatea ca bază
SLI: p50/p95/p99 latență, rata de eroare, saturație (CPU/heap/FD/IOPS), drop/timeout, adâncime coadă.
Urme: pentru a găsi blocaje sub eșec.
Metrica rezistenței semantice: rata de succes grațioasă-degradă, rata cererii de vărsare, rata de auto-vindecare (MTTR).
Experimente de etichetare: "haos. experiment_id', 'phase = injectare/recuperare' în evenimente/jurnale.
4) Catalog de injecții defecte
Rețea: întârziere/jitter, pierdere/duplicate/reordonare, limitare lățime de bandă, furtuni izbucni, pauze TLS.
Gazdă: limită CPU, scurgeri de memorie/limite, pauze GC, epuizare descriptor, "înclinare ceas'.
Stocare: latență crescândă, EROFS, ENOSPC, degradare replică, pierderea liderului.
Dependențe: 5xx/429, încetinire, DNS flapping, certificate învechite, rată-limită, „răspunsuri parțiale”.
Date: scrieți corupție, „găuri” în fluxuri, duplicate de evenimente, conflicte de versiuni.
Operațiuni: eliberare nereușită, feature flag, config drift, eroare manuală (ca parte a simulării).
5) Modele de stabilitate (ce să verificați)
Jitter retrage și timeout-uri pe fiecare RPC.
Întrerupător de circuit (deschidere/semi-deschidere, recuperare exponențială).
Pereți etanși (izolarea bazinelor/cozilor la domeniile critice).
Load Shedding (resetați cererile cu prioritate scăzută atunci când sunt saturate).
Backpressure (semnale în sus lanțul, limitele de concurență).
Idempotență (chei de idempotență pe „efecte secundare”).
Caching și stive în caz de degradare a sursei.
Degradare grațioasă (răspunsuri ușoare, date vechi, caracteristici de dezactivare).
Timeout-buget.
Atomicitate/compensare (Saga/Outbox/Inbox tranzactional).
Cvorumuri și replicare (cvorumuri R/W, degradarea consistenței pentru disponibilitate).
Anti-entropie/reluare (recuperare din găurile de evenimente).
6) Prescripții pentru injecții și așteptări (pseudocod)
Retray cu jitter și întrerupător
for attempt in 1..N:
if breaker. open(): return fallback()
res = call(dep, timeout = base 0. 8)
if res. ok: return res sleep(exp_backoff(attempt) jitter(0. 5..1. 5))
if attempt == N: breaker. trip()
return fallback()
Umbrire și Backprescher
if queue. depth() > HIGH cpu. load() > 0. 85:
if request. priority < HIGH: return 503_SHED limiter. acquire () # constrain concurrency
Idempotenta
key = hash("payout:"+external_id)
if store. exists(key): return store. get(key)
result = do_side_effect()
store. put(key, result, ttl=30d)
return result
7) Experimente: scenarii și ipoteze
7. 1 „Dependenţă lentă”
Injecţie: + 400 ms p95 la API extern.
Așteptare: creștere temporală ≤ X%, deschiderea întrerupătorului, răspunsuri de rezervă, economisirea serviciului p99 <SLA, fără cascadă în timpul retroactivelor.
7. 2 „Pierderea parțială a memoriei cache”
Injecție: eșec de 50% din Redis/Cache noduri shard.
Așteptare: ratat crescut, dar fără avalanșă la sursă (solicitare TTL coalescing/imuabil), încălzire automată și recuperare.
7. 3 „Split-creier în baza de date”
Injecție: Pierderea liderului, treceți la replică.
Așteptare: negarea pe termen scurt a înregistrărilor, citiți din cvorum, fără pierderi de date, Outbox nu pierde mesajele.
7. 4 „ENOSPC/disc complet”
Injecție: disc 95-100%.
Așteptare: rotirea de urgență a jurnalelor, eșecul caracteristicilor non-blocante, siguranța jurnalelor critice (WAL), alerte și autolichide.
7. 5 „Explozie de trafic”
Injecţie: × 3 SPR la punctul final fierbinte 10 min.
Așteptări: umbrire cu prioritate scăzută, p95 stabil pentru căile „nucleare”, creșterea cozii în limite, fără furtuni DLQ.
7. 6 „Ceas Skew”
Injecție: schimbarea timpului nodului cu +/ − 2 min.
Așteptare: TTL/semnături corecte (leway), cronometre monotonice în retroys, jetoane valabile cu derivă acceptabilă.
8) Medii și siguranța experimentelor
Începeți cu pre-prod, date sintetice, configurații/topologie cât mai aproape de produs.
În vânzări - numai ferestre controlate, steaguri, amplitudine pas cu pas, auto-rollback, „buton roșu”.
Guardrails: limite RPS/bug, paznici SLO, blocarea eliberărilor în timpul incidentelor critice.
Este necesar un runbook: cum să se rostogolească înapoi, pe cine să sune, unde să se uite.
9) Automatizare și CI/CD
Catalog de experimente ca cod (YAML/DSL): obiective, injecții, metrici, praguri, rollback „butoane”.
Fum-haos în fiecare eliberare: injecții scurte (de ex. 2 min + 200 ms de dependență) în etapă.
Matrix Night Rulează - Servicii × moduri de eșec
Poarta de lansare: interzicerea implementării dacă stabilitatea este sub prag (de exemplu, „acoperirea de rezervă <95%” sub „dependența lentă”).
10) Date și consecvență
Verificați compensația (Saga): operațiunile parțial efectuate trebuie aduse într-o stare convenită.
Reluări de testare/duplicate de evenimente, livrare în afara comenzii, găuri și reluări.
Verificați invarianții de domeniu după eșecuri: soldul nu este negativ, tranzacțiile nu se blochează, limitele nu sunt încălcate.
11) Anti-modele
Testați numai calea fericită și încărcați fără eșecuri.
Retrai fără jitter → o furtună sub degradare.
Nici un buget global de timeout → termene în cascadă.
Un singur bazin pentru toate sarcinile → nici o izolare (pereți etanși).
Cozile „infinite” → o creștere a latenței/PDE.
Telemetria zero a experimentelor → practicile haosului „orb”.
Haos în vânzare fără rollback/limite/proprietar responsabil.
12) Lista de verificare a arhitectului
1. Ipoteza stării de echilibru şi SLO definite?
2. Fiecare RPC are timeout, jitter se retrage, întrerupătoare?
3. Implementat pereți etanși, limitatoare, backpressure, load-shedding?
4. Cache de echilibru: coalescing, cache de protecție furtună, încălzire?
5. Outbox/Saga pentru efecte secundare, chei idempotente?
6. Cvorumuri/replicare/feilover testate?
7. Există un catalog de experimente, haos de noapte și porți în CI/CD?
8. Metrica/urme marchează experimente, există tablouri de bord?
9. Runbook "și" butonul roșu "gata, responsabilitatea atribuită?
10. Zile regulate de joc cu Dev/SRE/Support?
13) Mini Instrumente și scenarii de probă (Schițe YAML)
Rețea (tc/netem)
yaml experiment: add-latency target: svc:payments inject:
netem:
delay_ms: 300 jitter_ms: 50 loss: 2%
duration: 10m guardrails:
error_rate: "< 1%"
p95_latency: "< 400ms"
CPU/Heap
yaml inject:
cpu_burn: { cores: 2, duration: 5m }
heap_fill: { mb: 512 }
Dependență
yaml inject:
dependency:
name: currency-api mode: slow p95_add_ms: 500 fallback_expectation: "serve stale rates ≤ 15m old"
Concluzie
Testarea rezilienței nu este un „truc haos”, ci o disciplină care face sistemul previzibil sub erori. Ipoteze clare, telemetrie, un catalog de experimente controlate și modele încorporate în arhitectură (timeout, breakers, izolare, idempotence) transformă potențialele incidente în scenarii controlate. Echipa primește încredere în versiuni, iar utilizatorii primesc un serviciu stabil chiar și în condiții de eșecuri.