Projektowanie pod kątem samonaprawiania
Projektowanie swojej aplikacji jako samonaprawialnej w przypadku wystąpienia błędów
W systemie rozproszonym powinny wystąpić błędy. Sprzęt może ulec awarii. W sieci mogą się pojawić przejściowe błędy. Rzadko cała usługa, centrum danych, a nawet region świadczenia usługi Azure doświadczają zakłóceń, jednak nawet te muszą być zaprojektowane pod kątem architektury obciążenia. Odporność i odzyskiwanie należy rozwiązać na wczesnym etapie projektowania obciążenia.
W związku z tym należy zaprojektować aplikację, która jest samonaprawiona, gdy wystąpią błędy. Wymaga to podejścia trzytorowego:
- Wykrywanie błędów.
- Bezpieczna reakcja na błędy.
- Rejestrowanie i monitorowanie niepowodzeń w celu udzielenia szczegółowych informacji operacyjnych.
Sposób reagowania na określony typ awarii zależy od wymagań dotyczących dostępności aplikacji. Jeśli na przykład potrzebujesz wysokiej dostępności, możesz wdrożyć w wielu strefach dostępności w regionie. Aby uniknąć awarii, nawet w mało prawdopodobnym przypadku wystąpienia zakłóceń w całym regionie świadczenia usługi Azure możesz automatycznie przejść w tryb failover do regionu pomocniczego podczas awarii regionalnej. Jednak spowoduje to naliczenie wyższych kosztów i potencjalnie niższą wydajność niż wdrożenie w jednym regionie.
Ponadto nie należy brać pod uwagę jedynie poważnych wydarzeń, takich jak regionalne awarie, które zazwyczaj występują rzadko. Równie, a może nawet bardziej, istotne jest skoncentrowanie się na obsłudze lokalnych, krótkotrwałych awarii, takich jak awarie połączenia sieciowego lub nieudane połączenia z bazą danych.
Zalecenia
Użyj składników rozdzielonych, które komunikują się asynchronicznie. W idealnym przypadku składniki są oddzielone od czasu i przestrzeni. Oddzielenie w czasie oznacza, że składniki nie muszą być obecne w tym samym czasie, aby możliwe było komunikację. Rozdzielenie w przestrzeni oznacza, że nadawca i odbiorca nie muszą działać w tym samym procesie, ale mogą wszędzie tam, gdzie jest bardziej wydajne. Składniki rozdzielone najlepiej używają zdarzeń do komunikowania się ze sobą. Pomaga to zminimalizować ryzyko awarii kaskadowych.
Ponawianie próby w przypadku operacji zakończonych niepowodzeniem. Przejściowe błędy mogą wystąpić z powodu chwilowej utraty łączności sieciowej, porzuconego połączenia z bazą danych lub przekroczenia limitu czasu, gdy usługa jest zajęta. Wbuduj logikę ponowień w aplikację w celu obsługi błędów przejściowych. W przypadku wielu usług platformy Azure zestaw SDK klienta implementuje automatyczne ponawianie prób. Aby uzyskać więcej informacji, zobacz Obsługa błędów przejściowych i wzorzec ponawiania prób.
Ochrona zdalnych usług ulegających awarii (Wyłącznik). Warto ponowić próbę po błędzie przejściowym, ale jeśli błąd będzie się powtarzać, może wystąpić zbyt wiele wywołań usługi, która uległa awarii. Może to prowadzić do błędów kaskadowych w miarę tworzenia kopii zapasowej żądań. Użyj wzorca wyłącznika, aby szybko zakończyć się niepowodzeniem (bez wykonywania zdalnego wywołania), gdy operacja prawdopodobnie zakończy się niepowodzeniem.
Izolowanie krytycznych zasobów (Gródź). Błędy w jednym podsystemie czasami mogą narastać kaskadowo. Może się tak zdarzyć, jeśli awaria powoduje, że niektóre zasoby, takie jak wątki lub gniazda, nie są zwalniane w odpowiednim czasie, co prowadzi do wyczerpania zasobów. Aby tego uniknąć, użyj wzorca bulkhead, aby podzielić system na izolowane grupy, aby awaria w jednej partycji nie obniżyła całego systemu.
Wyrównywanie obciążenia. Aplikacje mogą wystąpić nagłe wzrosty ruchu, który może przeciążać usługi zaplecza. Aby tego uniknąć, użyj wzorca bilansowania obciążenia opartego na kolejce, aby kolejkować elementy robocze do uruchamiania asynchronicznie. Kolejka działa jak bufor, który wygładza skoki obciążenia.
Tryb failover. Jeśli dane wystąpienie jest nieosiągalne, przejdź do trybu failover do innego wystąpienia. W przypadku elementów bezstanowych, takich jak serwer internetowy, umieść kilka wystąpień za modułem równoważenia obciążenia lub menedżerem ruchu. W przypadku elementów, które przechowują stan, takich jak baza danych, zastosuj repliki i tryb failover. W zależności od magazynu danych i sposobu ich replikacji aplikacja może mieć do czynienia ze spójnością ostateczną.
Kompensowanie nieudanych transakcji. Ogólnie rzecz biorąc, unikaj transakcji rozproszonych, ponieważ wymagają one koordynacji między usługami i zasobami. Zamiast tego twórz operacje z mniejszych, oddzielnych transakcji. Jeśli operacja zakończy się niepowodzeniem po wykonaniu części kroków, za pomocą transakcji wyrównujących możesz cofnąć wszystkie kroki, które już się zakończyły.
Punkty kontrolne w przypadku długotrwałych transakcji. Punkty kontrolne mogą zapewnić odporność, jeśli długotrwała operacja zakończy się niepowodzeniem. Po ponownym uruchomieniu operacji (gdy na przykład zostanie ona podjęta przez inną maszynę wirtualną) będzie możliwe jej wznowienie od ostatniego punktu kontrolnego. Rozważ zaimplementowanie mechanizmu, który rejestruje informacje o stanie zadania w regularnych odstępach czasu, i zapisz ten stan w trwałym magazynie, do którego można uzyskać dostęp przez dowolne wystąpienie procesu uruchamiającego zadanie. W ten sposób, jeśli proces zostanie zamknięty, praca, którą wykonano, można wznowić z ostatniego punktu kontrolnego przy użyciu innego wystąpienia. Istnieją biblioteki, które zapewniają tę funkcję, takie jak NServiceBus i MassTransit. Są one przezroczystie utrwalane w stanie, w którym interwały są dopasowywane do przetwarzania komunikatów z kolejek w usłudze Azure Service Bus.
Zdaj sobie sprawność i zachowaj czas reakcji podczas awarii. Czasami nie można obejść problemu, ale można zapewnić ograniczoną funkcjonalność, która nadal jest użyteczna. Rozważmy aplikację, która wyświetla katalog książek. Jeśli aplikacja nie może pobrać miniatury okładki, może wyświetlać obraz zastępczy. Niekiedy całe podsystemy nie są niezbędne do działania aplikacji. Na przykład w witrynie handlu elektronicznego wyświetlanie zaleceń dotyczących produktów jest prawdopodobnie mniej krytyczne niż przetwarzanie zamówień.
Ograniczanie klientów. Czasami niewielka liczba użytkowników powoduje nadmierne obciążenie, co może zmniejszać dostępność aplikacji dla innych użytkowników. W takim przypadku ogranicz klienta przez pewien czas. Zobacz wzorzec ograniczania przepustowości.
Blokowanie złośliwych podmiotów. Ograniczenie klienta nie oznacza, że klient działał złośliwie. Po prostu klient przekroczył swój limit przydziału usługi. Jednak jeśli klient systematycznie przekracza swój limit przydziału lub zachowuje się nieprawidłowo w inny sposób, możesz go zablokować. Zdefiniuj proces poza pasmem, aby użytkownik mógł poprosić o odblokowanie.
Stosowanie wyboru lidera. Gdy konieczne jest koordynowanie zadania, wybierz koordynatora za pomocą wzorca Wybór lidera. Dzięki temu koordynator nie jest pojedynczym punktem awarii. Jeśli koordynator ulegnie awarii, zostanie wybrany nowy. Zamiast implementować algorytm wyboru lidera od podstaw, rozważ użycie gotowego rozwiązania, np. usługi Zookeeper.
Testowanie przy użyciu iniekcji błędów. Zbyt często zdarza się, że ścieżka powodzenia jest dobrze przetestowana, a ścieżka błędu nie jest. System może działać w środowisku produkcyjnym przez długi czas, zanim ścieżka błędu zostanie wykonana. Aby testować odporność systemu na błędy, wyzwalając rzeczywiste błędy albo symulując je, użyj iniekcji błędów.
Stosowanie inżynierii chaosu. Inżynieria chaosu rozszerza pojęcie iniekcji błędów przez losowe wstrzykiwanie awarii lub nietypowych warunków do wystąpień produkcyjnych.
Użyj stref dostępności. Wiele regionów świadczenia usługi Azure zapewnia strefy dostępności, które są izolowanymi zestawami centrów danych w regionie. Niektóre usługi platformy Azure można wdrożyć strefowo, co gwarantuje ich umieszczenie w określonej strefie i może pomóc zmniejszyć opóźnienie komunikacji między składnikami w tym samym obciążeniu. Alternatywnie niektóre usługi można wdrożyć z nadmiarowością strefy, co oznacza, że platforma Azure automatycznie replikuje zasób między strefami w celu zapewnienia wysokiej dostępności. Rozważ, które podejście zapewnia najlepszy zestaw kompromisów dla twojego rozwiązania. Aby dowiedzieć się więcej na temat projektowania rozwiązania w celu korzystania ze stref dostępności i regionów, zobacz Zalecenia dotyczące korzystania ze stref dostępności i regionów.
Aby uzyskać ustrukturyzowane podejście do samodzielnego naprawiania aplikacji, zobacz Projektowanie niezawodnych aplikacji dla platformy Azure.