Udostępnij za pośrednictwem


Wzorce odporności aplikacji

Napiwek

Ta zawartość jest fragmentem książki eBook, Architekting Cloud Native .NET Applications for Azure, dostępnej na platformie .NET Docs lub jako bezpłatny plik PDF do pobrania, który można odczytać w trybie offline.

Cloud Native .NET apps for Azure eBook cover thumbnail.

Pierwsza linia obrony to odporność aplikacji.

Chociaż możesz zainwestować dużo czasu na pisanie własnej struktury odporności, takie produkty już istnieją. Polly to kompleksowa biblioteka odporności platformy .NET i obsługa błędów przejściowych, która umożliwia deweloperom wyrażanie zasad odporności w sposób płynny i bezpieczny wątkowo. Aplikacja Polly jest przeznaczona dla aplikacji utworzonych przy użyciu programu .NET Framework lub .NET 7. W poniższej tabeli opisano funkcje odporności o nazwie policies, dostępne w bibliotece Polly. Można je stosować pojedynczo lub grupować razem.

Zasady Środowisko
Ponów próbę Konfiguruje operacje ponawiania prób dla wyznaczonych operacji.
Wyłącznik Blokuje żądane operacje dla wstępnie zdefiniowanego okresu, gdy błędy przekraczają skonfigurowany próg
Timeout Określa limit czasu trwania, przez który obiekt wywołujący może czekać na odpowiedź.
Gródź Ogranicza akcje do puli zasobów o stałym rozmiarze, aby zapobiec niepowodzeniom wywołań z zasób.
Pamięć podręczna Automatycznie przechowuje odpowiedzi.
Temat rezerwowy Definiuje zachowanie strukturalne po awarii.

Zwróć uwagę, jak na poprzedniej ilustracji zasady odporności dotyczą żądań komunikatów pochodzących z zewnętrznego klienta lub usługi zaplecza. Celem jest zrekompensowanie żądania usługi, która może być chwilowo niedostępna. Te krótkotrwałe przerwy zwykle manifestują się przy użyciu kodów stanu HTTP przedstawionych w poniższej tabeli.

Kod stanu HTTP Przyczyna
404 Nie znaleziono
408 Przekroczono limit czasu żądania
429 Zbyt wiele żądań (najprawdopodobniej zostało ograniczonych)
502 Zła brama
503 Usługa niedostępna
504 Limit czasu bramy

Pytanie: Czy ponowisz próbę kodu stanu HTTP 403 — Zabronione? L.p. W tym miejscu system działa prawidłowo, ale informuje obiekt wywołujący, że nie ma autoryzacji do wykonania żądanej operacji. Należy zachować ostrożność, aby ponowić próbę wykonania tylko tych operacji spowodowanych awariami.

Zgodnie z zaleceniami w rozdziale 1 deweloperzy firmy Microsoft tworzący aplikacje natywne dla chmury powinni kierować do platformy .NET. W wersji 2.1 wprowadzono bibliotekę HTTPClientFactory służącą do tworzenia wystąpień klienta HTTP na potrzeby interakcji z zasobami opartymi na adresach URL. Zastępowanie oryginalnej klasy HTTPClient, klasa fabryki obsługuje wiele rozszerzonych funkcji, z których jedna jest ścisłą integracją z biblioteką odporności Polly. Dzięki niemu można łatwo zdefiniować zasady odporności w klasie uruchamiania aplikacji w celu obsługi częściowych awarii i problemów z łącznością.

Następnie rozszerzmy wzorce ponawiania prób i wyłącznika.

Wzorzec ponawiania

W rozproszonym środowisku natywnym dla chmury wywołania usług i zasobów w chmurze mogą zakończyć się niepowodzeniem z powodu przejściowych (krótkotrwałych) awarii, które zwykle korygują się po krótkim czasie. Zaimplementowanie strategii ponawiania prób pomaga usłudze natywnej dla chmury ograniczyć te scenariusze.

Wzorzec ponawiania umożliwia usłudze ponowienie próby wykonania operacji żądania, która zakończyła się niepowodzeniem (konfigurowalna) liczbą razy z wykładniczo rosnącym czasem oczekiwania. Rysunek 6–2 przedstawia ponowienie próby w akcji.

Retry pattern in action

Rysunek 6–2. Wzorzec ponawiania próby w działaniu

Na poprzednim rysunku zaimplementowano wzorzec ponawiania dla operacji żądania. Jest on skonfigurowany tak, aby umożliwić maksymalnie cztery ponawianie prób przed niepowodzeniem z interwałem wycofywania (czas oczekiwania) rozpoczynającym się od dwóch sekund, co wykładniczo podwaja się dla każdej kolejnej próby.

  • Pierwsze wywołanie kończy się niepowodzeniem i zwraca kod stanu HTTP 500. Aplikacja czeka na dwie sekundy i ponawia próbę wywołania.
  • Drugie wywołanie również kończy się niepowodzeniem i zwraca kod stanu HTTP 500. Aplikacja podwoi teraz interwał wycofywania do czterech sekund i ponawia próbę wywołania.
  • Na koniec trzecie wywołanie powiedzie się.
  • W tym scenariuszu operacja ponawiania prób próbowałaby wykonać do czterech ponownych prób podczas podwojenia czasu trwania wycofywania przed niepowodzeniem wywołania.
  • Gdyby 4. próba ponawiania nie powiodła się, zostanie wywołana zasada powrotu, aby bezpiecznie poradzić sobie z problemem.

Ważne jest, aby zwiększyć okres wycofywania przed ponowną próbą wywołania, aby umożliwić samodzielne poprawianie czasu usługi. Najlepszym rozwiązaniem jest zaimplementowanie wykładniczo rosnącego wycofywania (podwojenie okresu ponawiania próby) w celu umożliwienia odpowiedniego czasu korekty.

Wzorzec wyłącznika

Chociaż wzorzec ponawiania prób może pomóc uratować żądanie splątane w częściowym błędzie, istnieją sytuacje, w których awarie mogą być spowodowane przez nieprzewidziane zdarzenia, które będą wymagać dłuższych okresów czasu do rozwiązania. Takie błędy mogą mieć różny stopień ważności — od częściowej utraty łączności do całkowitej awarii usługi. W takich sytuacjach nie ma sensu, aby aplikacja stale ponawiała próbę wykonania operacji, która prawdopodobnie nie powiedzie się.

Co gorsza, wykonywanie ciągłych operacji ponawiania prób w usłudze niereponsywnej może spowodować przejście do scenariusza samodzielnej odmowy usługi, w którym usługa jest zalana ciągłymi wywołaniami wyczerpującymi zasobami, takimi jak pamięć, wątki i połączenia bazy danych, powodując awarię niepowiązanych części systemu, które korzystają z tych samych zasobów.

W takich sytuacjach preferowane byłoby natychmiastowe niepowodzenie operacji i próba wywołania usługi tylko wtedy, gdy prawdopodobnie powiedzie się.

Wzorzec wyłącznika może uniemożliwić aplikacji wielokrotne wykonywanie operacji, która prawdopodobnie zakończy się niepowodzeniem. Po wstępnie zdefiniowanej liczbie wywołań zakończonych niepowodzeniem blokuje cały ruch do usługi. Okresowo umożliwia wywołanie wersji próbnej w celu ustalenia, czy usterka została rozwiązana. Rysunek 6–3 przedstawia wzorzec wyłącznika w działaniu.

Circuit breaker pattern in action

Rysunek 6–3. Wzorzec wyłącznika w działaniu

Na poprzedniej ilustracji do oryginalnego wzorca ponawiania prób dodano wzorzec wyłącznika. Zwróć uwagę, jak po 100 żądaniach, które zakończyły się niepowodzeniem, wyłącznik otwiera się i nie zezwala już na wywołania usługi. Wartość CheckCircuit ustawiona na 30 sekund określa, jak często biblioteka zezwala na przejście do usługi przez jedno żądanie. Jeśli to wywołanie powiedzie się, obwód zostanie zamknięty, a usługa będzie po raz kolejny dostępna dla ruchu.

Należy pamiętać, że intencja wzorca wyłącznika różni się od wzorca ponawiania. Wzorzec ponawiania umożliwia aplikacji ponawianie próby wykonania operacji w oczekiwaniu, że zakończy się powodzeniem. Wzorzec wyłącznika uniemożliwia aplikacji wykonywanie operacji, która może zakończyć się niepowodzeniem. Zazwyczaj aplikacja łączy te dwa wzorce przy użyciu wzorca ponawiania w celu wywołania operacji za pośrednictwem wyłącznika.

Testowanie pod kątem odporności

Testowanie odporności nie zawsze może odbywać się w taki sam sposób, w jaki testujesz funkcjonalność aplikacji (uruchamiając testy jednostkowe, testy integracji itd.). Zamiast tego należy przetestować sposób działania kompleksowego obciążenia w warunkach awarii, które występują tylko sporadycznie. Na przykład: wprowadzanie błędów przez awarie procesów, wygasłych certyfikatów, niedostępność usług zależnych itp. Struktury takie jak chaos-monkey mogą być używane do takich testów chaosu.

Odporność aplikacji jest koniecznością obsługi problematycznych żądanych operacji. Ale to tylko połowa historii. Następnie omówimy funkcje odporności dostępne w chmurze platformy Azure.