English· Español· Deutsch· Nederlands· Français· 日本語· ქართული· 繁體中文· 简体中文· Português· Русский· العربية· हिन्दी· Italiano· 한국어· Polski· Svenska· Türkçe· Українська· Tiếng Việt· Bahasa Indonesia

un

gość
1 / ?
powrót do lekcji

Trzy koncepcje awarii, które warto znać

Witaj

Systemy rozproszone ulegają awariom w określonych wzorcach. Gdy poznasz te wzorce, każdy raport po awarii stanie się ćwiczeniem rozpoznawczym, a nie zagadką.

Trzy koncepcje obejmują większość tego, co ma znaczenie w analizie awarii produkcyjnych:

Pojedynczy punkt awarii (SPOF): komponent, którego awaria powoduje zatrzymanie większego systemu. Często ukryty: serwer DNS, od którego wszyscy zależą; certyfikat, względem którego wszystko się odnawia; pojedynczy master bazy danych.

Awaria kaskadowa: awaria jednego komponentu wywołuje awarię innego, który z kolei wywołuje awarię kolejnego. Powolna baza danych powoduje przekroczenia limitów czasu (timeouts) w warstwie API, co prowadzi do ponowień żądań (retries), które obciążają bazę danych jeszcze bardziej, co z kolei powoduje kolejne przekroczenia limitów czasu. Fala uderzeniowa się rozprzestrzenia.

Promień rażenia (blast radius): jak duża część systemu ulega awarii, gdy jeden element zawiedzie. Wybory architektoniczne albo ograniczają, albo nieograniczają ten promień. Punkt pojedynczej awarii (SPOF) ma nieograniczony promień rażenia. Usługa zbudowana z przegródkami (bulkhead) ma ograniczony promień rażenia.

Na koniec tej lekcji będziesz w stanie:

- Identyfikować punkty pojedynczej awarii (SPOF) w architekturze poprzez jej analizę

- Rozpoznawać wzorce awarii kaskadowych: gromada grzmotów (thundering herd), burza ponowień (retry storm), kolejka śmierci (queue of death)

- Czytać rzeczywisty harmonogram zdarzeń i rozdzielać wyzwalacz od ukrytej wady, którą ten wyzwalacz ujawnił

- Pisać bezwinne (blameless) pozycje listy działań, które celują w systemy, a nie w ludzi, obejmujące zapobieganie / wykrywanie / odzyskiwanie

- Rozumować na temat przegródek (bulkheads) i wyłączników obwodu (circuit breakers) jako narzędzi ograniczających promień rażenia

Znajdź pojedynczy punkt awarii

Inspekcja warstwowej architektury

Rozważ małą architekturę webową:

- DNS: api.example.com -> pojedynczy adres IP serwera nazw 203.0.113.10 hostowany przez jednego dostawcę DNS

- CDN: pojedynczy dostawca CDN przed api.example.com

- Ingress: dwa maszyny proxy odwrotnego za balancerem obciążenia

- Backend: sześć replik API w dwóch strefach dostępności (po trzy w każdej strefie)

- Baza danych: jeden primarny + jeden replikata do odczytu, w tej samej strefie dostępności

- Cache: klastr Redis, trzy węzły rozmieszczone w tych samych dwóch strefach dostępności

Pytanie: które komponenty są SPOF? Wskazówka: SPOF to nie zawsze oczywisty typ „pojedynczy serwer”. Klastr trzech maszyn znajdujących się w jednej strefie dostępności jest SPOF w przypadku awarii tej strefy.

Zidentyfikuj co najmniej trzy SPOF w tej architekturze. Dla każdego z nich podaj, co ulega awarii, gdy do niej dochodzi, oraz zaproponuj konkretną zmianę, która usunie SPOF (bez przepisywania aplikacji).

Trzy klasyczne wzorce kaskadowe

Awarie przenoszą się przez zależności

Wzorzec 1: Tłum żądających (Thundering herd). Wspólny zasób (pamięć podręczna, blokada, baza danych) ulega awarii lub jest restartowany. Każdy klient, który od niego zależał, ponawia żądania jednocześnie. Ta fala żądań przytłacza to, co wraca do działania; ponowienia gromadzą się szybciej, niż proces odzyskiwania może je obsłużyć; odzyskiwanie nigdy się nie kończy.

Wzorzec 2: Burza ponowień (Retry storm). Usługa dół łańcucha (downstream) spowalnia. Wywołujący z góry łańcucha (upstream), zamiast zgłaszać błąd, ponawiają żądania. Ponowienia mnożą oryginalne obciążenie. Powolna usługa spowalnia jeszcze bardziej, wywołując kolejne ponowienia. Ostatecznie obciążenie przewyższa możliwości nawet zdrowej wersji usługi.

Wzorzec 3: Kolejka śmierci. Kolejka przetwarzania bez mechanizmu hamowania (backpressure) przyjmuje elementy szybciej, niż je przetwarza. Kolejka rośnie bez ograniczeń. Pamięć wyczerpuje się; konsument ulega awarii; jest restartowany; znajduje kolejną, jeszcze większą kolejkę; ulega awarii ponownie.

Wspólny mianownik: małe początkowe zaburzenie wywołuje pętlę sprzężenia zwrotnego dodatniego. Własna reakcja systemu wzmacnia awarię zamiast ją tłumić.

Mechanizmy tłumienia

Wykładnicze wycofywanie z jitterem. Klienci wykonujący ponowne próby czekają coraz dłużej, z losowym przesunięciem. Zapobiega zsynchronizowanym falom ponownych prób.

Wyłącznik obwodu (circuit breaker). Wywołujący śledzi wskaźnik awarii w dół łańcucha. Po przekroczeniu progu, wywołujący przestaje wysyłać żądania na czas okresu chłodzenia i natychmiast zwraca błędy dla własnych żądań. Zapobiega marnowaniu zasobów i pozwala systemowi docelowemu na odzyskanie.

Bulwark (Bulkhead). Izolacja zasobów dla każdego zależności. Basen połączeń A dla bazy danych, osobny basen połączeń B dla pamięci podręcznej. Powolna baza danych nie może wyczerpać wszystkich połączeń; wywołania do pamięci podręcznej kontynuują działanie.

Odrzucanie obciążenia (Load shedding). W przypadku przeciążenia, odrzucaj żądania na krawędzi systemu zamiast przyjmować je i powoli zawodzić. Odpowiedź 429 w 1 ms jest lepsza niż 500 po 30 sekundach.

Ciśnienie zwrotne (Backpressure). Zwolnij producentów, gdy konsumenci nie nadążają. Kolejki stają się ograniczone; nadawcy są blokowani; pierwotne źródło pracy odczuwa opór.

Awaria kaskadowa: wyzwalacz -> amplifikacja -> załamanie, z mechanizmami tłumiącymi

Diagnoza awarii kaskadowej

Warstwa API zespołu ulega awarii podczas rutynowego przełączania bazy danych. Oś czasu:

- 14:00:00 — operator promuje bazę danych standby. Oczekiwana niedostępność: ~10 sekund.

- 14:00:08 — baza danych primary jest niedostępna. Żądania warstwy API zaczynają kończyć się błędami połączenia z bazą danych.

- 14:00:08 — warstwa API wykonuje ponowne próby (domyślna konfiguracja: 5 ponowień, bez opóźnienia, w odstępach 100 ms).

- 14:00:11 — baza standby została promowana i przyjmuje nowe połączenia.

- 14:00:11 — warstwa API otwiera jednocześnie tysiące nowych połączeń z bazą danych (każdy replikant × każde równoległe żądanie × każde ponowienie).

- 14:00:13 — pula połączeń nowej bazy primary jest wyczerpana; nowe połączenia są odrzucane.

- 14:00:13-14:05:00 — replikanty warstwy API wyczerpują pule połączeń, wyrzucają wyjątki, ulegają awarii, restartują i powtarzają ten cykl.

- 14:05:00 — operator ręcznie zatrzymuje ruch warstwy API; baza danych stabilizuje się.

- 14:10:00 — zakończenie stopniowego przywracania ruchu. Łączny czas przestoju: ~10 minut (w porównaniu z oczekiwanym ~10 sekundami).

Zidentyfikuj wzorzec kaskadowy, który wystąpił, nazwij mechanizmy tłumienia, które zapobiegłyby mu (przynajmniej dwa), oraz wyjaśnij, dlaczego przełączenie awaryjne z węzła głównego na zapasowy (które miało być 10-sekundowym „przepraskiem”) spowodowało 10-minutowy przestój.

DNS SERVFAIL: Dwa nakładające się na siebie defekty

Postmortem w realnym kształcie

Poniżej znajduje się zanonimizowana wersja rzeczywistego incydentu. Nazwy dostawców zostały zmienione, adresy IP zanonimizowane; kształt, oś czasu oraz wnioski są prawdziwe.

Podsumowanie

Strona example.com zwracała SERVFAIL ze wszystkich publicznych resolverów DNS przez około 3–4 godziny. Wszystkie pozostałe 46 strefy na tym samym serwerze DNS master nie były dotknięte. Przyczyna główna: dwa nakładające się na siebie defekty.

1. Dostawca A (wtórny dostawca DNS) dodał nowy wewnętrzny adres IP synchronizacji, który nie znajdował się na liście dozwolonych allow-axfr-ips serwera primary.

2. Strefa example.com miała konflikt CNAME naruszający RFC, istniejący od kilku lat (demo.example.com miał zarówno rekord CNAME, jak i rekordy MX/TXT na tej samej etykiecie), co spowodowało, że Dostawca A odrzucił strefę podczas świeżego AXFR.

Oś czasu (UTC)

- ~15:00 — Dostawca A dodaje nowy IP synchronizacji 198.51.100.42 do swojej infrastruktury

- 15:02 — w logach głównego DNS pojawia się pierwszy wpis AXFR-out denied dla 198.51.100.42 (brak alertowania na ten sygnał)

- ~18:00 — osiągnięto okno wygaśnięcia SOA; Dostawca A usuwa strefę example.com z pamięci podręcznej

- ~18:30 — wykryto zewnętrznie błąd SERVFAIL

- ~19:45 — zidentyfikowano przyczynę źródłową

- 20:00 — 198.51.100.42 dodano do allow-axfr-ips; zainicjowano ponowne uruchomienie serwera głównego

- 20:05 — wysłano powiadomienie NOTIFY; zainicjowano AXFR; strefa nadal zwraca SERVFAIL (konflikt CNAME)

- 20:07 — check-zone wykrywa 1 błąd: konflikt CNAME dla demo.example.com

- 20:09 — rekord CNAME zastąpiony rekordem A; kontrola strefy czysta (0 błędów)

- 20:10 — wysłano NOTIFY; zakończono AXFR; Dostawca A zaczyna serwować strefę

- 20:11 — dig @8.8.8.8 example.com A zwraca poprawny adres IP — ROZWIĄZANO

Dlaczego tylko example.com?

Wszystkie 47 stref korzysta z tego samego DNS primary. Blokowanie IP przez AXFR wpłynęło na wszystkie strefy. Jednak tylko example.com miało konflikt CNAME, a tylko example.com wymagało świeżego AXFR w momencie, gdy egzekwowano zakaz. Inne strefy odświeżyły się przed zakazem lub jeszcze nie wymagały tego.

Ukryta wada

Konflikt CNAME w demo.example.com istniał od lat. Działał, ponieważ primary serwowało strefę z bazy danych (było wyrozumiałe wobec naruszeń RFC), a Dostawca A serwował ze starych danych w pamięci podręcznej sprzed wprowadzenia naruszenia. Gdy Dostawca A wyczyścił pamięć podręczną i potrzebował świeżych danych, naruszenie ujawniło się.

Wyzwalacz

Dostawca A cicho dodał nowy adres IP synchronizacji. Lista dozwolonych adresów na serwerze głównym nie zawierała tego adresu. AXFR został odrzucony. Trzy godziny później (po wygaśnięciu SOA) Dostawca A usunął strefę. Ukryta wada ujawniła się, gdy system próbował się odzyskać.

Napisz bezosobowe działania naprawcze

Bezosobowość: Celuj w systemy, nie w ludzi

Bezosobowe działanie naprawcze wskazuje, co system powinien robić inaczej, a nie co dana osoba powinna robić inaczej. „Przeszkolić operatora” to działanie obwiniające. „Dodać automatyczną weryfikację, która wychwyci to przed wdrożeniem”, to działanie bezosobowe.

Dobre bezosobowe działania naprawcze grupują się w trzech wymiarach:

- Prewencja: sprawienie, by zła rzecz była trudniejsza lub niemożliwa

- Wykrywanie: zauważenie tego wcześniej, jeśli do tego dojdzie

- Odzyskiwanie: ograniczenie szkód, gdy do tego dojdzie

Każdy element powinien wskazywać (1) konkretną zmianę systemową, (2) zespół odpowiedzialny oraz (3) wymiar, któremu służy.

Napisz trzy bezwinne (blameless) elementy akcji dotyczące powyższego postmortemu DNS-SERVFAIL. Rozmieść je w wymiarach: zapobieganie / wykrywanie / odzyskiwanie (jeden na każdy wymiar). Każdy element musi wskazywać konkretną zmianę systemową oraz zespół odpowiedzialny. Nie wskazuj żadnej osoby jako przyczyny.

Komory, które toną bez statku

Zapożyczone z inżynierii okrętowej

Statki posiadają wodoszczelne przegrody: pionowe ściany dzielące kadłub na komory. Jedna komora może się zalać, nie zatapiając statku; inna może ulec awarii bez wpływu na pozostałe.

Systemy rozproszone pożyczają to samo słowo i ten sam pomysł.

Wzorzec przegród (bulkhead): izolacja zasobów dla każdego zależności. Usługa wywołująca trzy API w dół używa trzech osobnych puli połączeń, trzech osobnych puli wątków i trzech osobnych budżetów ponowień. Wolna lub awaryjna zależność nie może zużyć zasobów przeznaczonych dla pozostałych dwóch.

Bez przegród: jedna wolna zależność wyczerpuje wspólną pulę wątków; wywołania do innych zależności blokują się, czekając na wątki; cała usługa staje się nieodpowiadająca.

Z przegrodami: jedna wolna zależność wyczerpuje własną pulę; wywołania do niej kończą się błędem szybko; wywołania do innych zależności przebiegają normalnie; promień rażenia pozostaje ograniczony do awaryjnej zależności.

Wyłączniki obwodu

Wzór obwodu rozłącznego (circuit breaker): stanowy wrapper wokół zależności w dół łańcucha, który śledzi wskaźnik awarii. Trzy stany:

- Zamknięty (normalny): wywołania przechodzą dalej. Awarie są liczone.

- Otwarty (wyłączony): po przekroczeniu progu awarii (np. 50% awarii w ciągu ostatnich 30 sekund), obwód się otwiera. Wywołania kończą się błędem natychmiast, bez próby dotarcia do zależności. Oszczędza to czas wywołującemu; chroni zależność przed odbieraniem obciążenia, gdy jest niezdrowa.

- Półotwarty (testowy): po okresie chłodzenia, obwód przepuszcza niewielki ułamek wywołań. Jeśli się powiedzą, wraca do stanu zamkniętego (normalnego). Jeśli się nie powiedzą, otwiera się ponownie na kolejny okres chłodzenia.

Kluczowa obserwacja: obwód rozłączny zapobiega marnowaniu wysiłku w okresach, gdy stan jest znany jako niezdrowy, oraz daje zależności szansę na odzyskanie sprawności bez ciągłego obciążenia.

Przegrody (bulkheads) ograniczają promień rażenia. Obwody rozłączne zapobiegają samonakręcaniu się rażenia.

Ogranicz promień rażenia

Twoja usługa API wywołuje cztery usługi w dół łańcucha: Usługę Użytkownika, Usługę Rekomendacji, Usługę Powiadomień oraz zewnętrzne API Płatności. Zespół usłyszał, że „Usługa Rekomendacji bywa nieco niestabilna” i chce upewnić się, że gdy dojdzie do jej awarii, reszta systemu pozostanie zdrowa.

Dziś usługa korzysta z jednego wspólnego puli wątków 200 wątków oraz jednego wspólnego puli połączeń HTTP. Wszystkie cztery zależności konkurują o te zasoby. Nie ma tu obwodu rozłącznika (circuit breakera).

Zaprojektuj architekturę z przegrodami (bulkhead) i obwodem rozłącznika (circuit breaker) dla tej usługi API. Bądź konkretny: jak podzielić pule wątków / połączeń między cztery zależności, jakie progi obwodu rozłącznika mają sens dla niestabilnej Usługi Rekomendacji oraz co powinna robić API widoczne dla użytkownika, gdy Usługa Rekomendacji ma otwarty obwód rozłącznika?

Zaprojektuj przegląd trybów awarii

Synteza

Nauczyłeś się wykrywać pojedyncze punkty awarii (SPOF) przez inspekcję, rozpoznawać wzorce kaskadowych awarii, rozdzielać przyczynę wyzwalającą od ukrytej wady przy czytaniu analizy postmortem, pisać bezwinne pozycje akcji w obszarach zapobiegania / wykrywania / odzyskiwania oraz ograniczać promień rażenia za pomocą grodzi (bulkheads) + obwodów rozłącznych (circuit breakers) + eleganckiego degradowania.

Zastosuj wszystkie pięć.

Twoja drużyna wdraża nową usługę search.example.com, która zależy od trzech usług po stronie odbiorcy: głównego indeksu wyszukiwania (index.example.com), usługi analitycznej (analytics.example.com) oraz usługi rekomendacji (recs.example.com). Drużyna chce, abyś poprowadził „przegląd trybów awarii” przed wdrożeniem.

Szkicuj przegląd trybów awarii, który byś poprowadził. Uwzględnij: jak ujawniłbyś pojedyncze punkty awarii (jedna technika), jak zapobiegłbyś kaskadowej awarii między usługą wyszukiwania a jej trzema usługami po stronie odbiorcy (dwa wzorce), jedną konkretną pozycję akcji dla usługi rekomendacji (którą drużyna oznaczyła jako najmniej niezawodną) oraz jaki monitoring wymagałbyś, aby był gotowy w momencie wdrożenia.

Kierunek dalszego rozwoju tego kursu

Kierunek dalszego rozwoju tego kursu

Teraz potrafisz rozpoznać SPOF, zidentyfikować kaskadę, produktywnie czytać raporty po awariach, pisać bezwinne elementy akcji oraz ograniczać promień rażenia przez odpowiedni projekt.

Ostatnia lekcja w tym kursie (cs_distsys_observability_and_capacity) uczy, co mierzyć, aby wykryć problem, zanim zrobią to użytkownicy. Sprawdzanie stanu, punkty końcowe wersji, cztery sygnały złote na warstwie proxy oraz jak decyzje dotyczące pojemności awaryjnej wiążą się z obserwowanymi danymi.

Lekcja towarzysząca: geometry_of_failure_modes_and_blast_radius wyprowadza centralność międzywęzłową (który węzeł grafu jest wąskim gardłem) oraz minimalne cięcie (granica promienia rażenia).

Brawo. W drogę.