Badanie stabilności
1) Podstawowe koncepcje i cele
Niezawodność - prawdopodobieństwo wykonania; odporność-Zachowanie podczas i po awarii.
SLO/błędny budżet: kryteria „akceptowalności” degradacji.
Hipoteza stanu stacjonarnego: formalne oczekiwanie na stabilne wskaźniki (np. p95 <200 ms, częstość błędów <0. 5%). Eksperyment jest uważany za udany, jeśli hipoteza jest utrzymana.
Rodzaje awarii: sieć (opóźnienie, utrata/duplikaty, przerwy), obliczenia (procesor, pamięć), przechowywanie (I/O, wyczerpanie dysku), zależności (5xx, timeouts, rate-limit), logiczne (incydenty częściowe, „powolne rozkład”), operacyjne (zwolnienie, config), „ciemność” (podział mózgu, zmiany godzinowe).
2) Piramida zrównoważonego rozwoju
1. Testy jednostkowe awarii logicznych (przekładki, idempotencja, timeouts).
2. Adaptery z wtryskiem uszkodzenia (Testcontainers/tc-netem).
3. Integracja/system z siecią/bazą danych/buforami i profilami świata rzeczywistego.
4. Eksperymenty chaosu w pre-prod (a następnie ograniczone w prod) na książkach startowych.
5. Dzień gry - scenariusz ćwiczeń zespołu (ludzie + narzędzia).
3) Obserwowalność jako podstawa
SLI: p50/p95/p99 opóźnienie, prędkość błędu, nasycenie (CPU/hałda/FD/IOPS), spadek/czas, głębokość kolejki.
Ślady: znaleźć wąskie gardła w przypadku awarii.
Wskaźniki odporności semantycznej: szybkość sukcesu wdzięku-degradacji, szybkość rzucania żądania, szybkość samouzdrawiania (MTTR).
Eksperymenty z etykietowaniem: "chaos. experiment_id', 'faza = wstrzyknięcie/odzyskanie' w zdarzeniach/dziennikach.
4) Katalog wtrysku usterek
Sieć: opóźnienie/jitter, utrata/duplikaty/ponowne zamawianie, ograniczenie przepustowości, burze, przerwy TLS.
Host: limit procesora, wycieki pamięci/limity, pauzy GC, wyczerpanie deskryptora, „skew zegara”.
Przechowywanie: zwiększenie opóźnień, EROFS, ENOSPC, degradacja repliki, utrata lidera.
Zależności: 5xx/429, spowolnienie, flapping DNS, przestarzałe certyfikaty, limit stawki, „częściowe odpowiedzi”.
Dane: pisać korupcję, „dziury” w strumieniach, duplikaty zdarzeń, konflikty wersji.
Operacje: nieudane zwolnienie, flaga funkcji, dryf konfiguracyjny, błąd ręczny (w ramach symulacji).
5) Wzory stabilności (co sprawdzić)
Jitter odtwarza i timeouts na każdym RPC.
Wyłącznik (otwarcie/półotwór, odzyskiwanie wykładnicze).
Grodzie (izolacja puli/kolejek do domen krytycznych).
Load Shedding (zresetuj żądania o niskim priorytecie, gdy są nasycone).
Ciśnienie wsteczne (sygnalizuje łańcuch, limity współistnienia).
Idempotencja (klucze idempotencji na „efekty uboczne”).
Buforowanie i stosy w przypadku degradacji źródła.
Wdzięczna degradacja (lekkie odpowiedzi, stałe dane, funkcje wyłączania).
Timeout-budget.
Atomicity/compensation (Saga/Outbox/Transactional Inbox).
Kworum i replikacja (kworum R/W, degradacja konsystencji dla dostępności).
Anty-entropia/powtórka (odzyskiwanie z otworów zdarzeń).
6) Recepty na zastrzyki i oczekiwania (pseudokoda)
Retray z jitter i breaker
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()
Shading i Backprescher
if queue. depth() > HIGH cpu. load() > 0. 85:
if request. priority < HIGH: return 503_SHED limiter. acquire () # constrain concurrency
Idempotencja
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) Eksperymenty: Scenariusze i hipotezy
7. 1 „Powolna zależność”
Wstrzyknięcie: + 400 ms p95 do zewnętrznego API.
Oczekiwanie: wzrost czasu ≤ X%, otwarcie wyłącznika, reakcje awaryjne, oszczędność usługi p99 <SLA, brak kaskady podczas retras.
7. 2 „Częściowa utrata pamięci podręcznej”
Wstrzyknięcie: awaria 50% węzłów odłamkowych Redis/Cache.
Oczekiwanie: zwiększona miss, ale bez lawiny do źródła (żądanie koalescencji/immutable TTL), automatyczne ogrzewanie i odzyskiwanie.
7. 3 „Podział mózgu w bazie danych”
Wtrysk: Utrata lidera, przełącznik na replikę.
Czekanie: krótkoterminowe zaprzeczanie rekordom, odczytywanie z kworum, brak utraty danych, Outbox nie traci wiadomości.
7. 4 „ENOSPC/dysk pełny”
Wstrzyknięcie: 95-100% płyty.
Oczekiwanie: awaryjny obrót kłód, awaria funkcji bez blokowania, bezpieczeństwo dzienników krytycznych (WAL), alerty i autolikwidy.
7. 5 „Pęknięcie ruchu”
Wtrysk: × 3 RPS do gorącego punktu końcowego 10 min.
Oczekiwanie: niski priorytet zacienienia, stabilny p95 dla „jądrowych” ścieżek, wzrost kolejki w granicach, bez burz DLQ.
7. 6 „Zegar Skew”
Wstrzyknięcie: przesunięcie czasu węzła o +/− 2 min.
Oczekiwanie: poprawne TTL/podpisy (wolna wolna droga), monotoniczne timery w przekładniach, ważne żetony z dopuszczalnym dryfem.
8) Środowisko i bezpieczeństwo eksperymentów
Zacznij od pre-prod, syntetycznych danych, konfiguracji/topologii tak blisko produktu, jak to możliwe.
W sprzedaży - tylko kontrolowane okna, flagi, amplituda krok po kroku, auto-rollback, „czerwony przycisk”.
Poręcze: limity RPS/błędów, osłony SLO, blokowanie zwolnień podczas krytycznych incydentów.
Wymagana jest książka startowa: jak odwrócić, do kogo zadzwonić, gdzie szukać.
9) Automatyzacja i CI/CD
Katalog eksperymentów jako kod (YAML/DSL): gole, zastrzyki, mierniki, progi, przyciski wsteczne ".
Chaos dymu w każdym zwolnieniu: krótkie wstrzyknięcia (np. 2 min + 200 ms do uzależnienia) na etapie.
Matrix Night Runs - Usługi × Tryby awaryjne
Brama uwolnienia: zakaz stosowania, jeżeli stabilność jest poniżej progu (na przykład „pokrycie awaryjne <95%” w ramach „powolnej zależności”).
10) Dane i spójność
Rekompensata z tytułu kontroli (Saga): częściowo wykonane operacje muszą zostać wprowadzone do uzgodnionego stanu.
Powtórki testowe/duplikaty zdarzeń, dostawa poza zamówieniem, otwory i powtórki.
Sprawdź niezmienne domeny po awariach: saldo nie jest ujemne, transakcje nie utkną, limity nie są naruszane.
11) Anty-wzory
Testuj tylko szczęśliwą ścieżkę i obciążenie bez awarii.
Retrai bez jitter → burza pod degradacją.
Brak globalnego budżetu harmonogramu → kaskadowe terminy.
Pojedynczy basen dla wszystkich zadań → brak izolacji (grodzie).
„Nieskończone” kolejki → wzrost opóźnień/PDE.
Zero telemetrii eksperymentów → „ślepe” praktyki chaosu.
Chaos w sprzedaży bez zwrotu/limitów/odpowiedzialnego właściciela.
12) Lista kontrolna architekta
1. Hipoteza stanu stacjonarnego i zdefiniowane SLO?
2. Każdy RPC ma czas, rekolekcje jitter, wyłączniki?
3. Zaimplementowane grodzie, ograniczniki, ciśnienie wsteczne, odchudzanie?
4. Cache stabilne: koalescencja, ochrona przed burzą pamięci podręcznej, rozgrzewka?
5. Outbox/Saga na efekty uboczne, idempotentne klucze?
6. Sprawdzono kworum/replikację/feilover?
7. Czy istnieje katalog eksperymentów, nocny chaos i bramy w CI/CD?
8. Metryka/ślady oznaczają eksperymenty, czy są deski rozdzielcze?
9. Runbook i „czerwony przycisk” gotowe, odpowiedzialność przypisana?
10. Regularne dni gry z Dev/SRE/Support?
13) Mini narzędzia i przykładowe scenariusze (szkice YAML)
Sieć (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"
Procesor/hałd
yaml inject:
cpu_burn: { cores: 2, duration: 5m }
heap_fill: { mb: 512 }
Zależność
yaml inject:
dependency:
name: currency-api mode: slow p95_add_ms: 500 fallback_expectation: "serve stale rates ≤ 15m old"
Wnioski
Testowanie odporności nie jest „sztuczką chaosu”, ale dyscypliną, która sprawia, że system jest przewidywalny pod usterkami. Jasne hipotezy, telemetria, katalog kontrolowanych eksperymentów i wbudowane wzory w architekturze (timeouts, breakers, izolacja, idempotencja) przekształcają potencjalne incydenty w kontrolowane scenariusze. Zespół zyskuje zaufanie do wydań, a użytkownicy otrzymują stabilną usługę nawet w warunkach awarii.