Ćwiczenie — implementowanie odporności aplikacji

Ukończone

Projekt eShop ma dwie usługi, które komunikują się ze sobą przy użyciu żądań HTTP. Usługa Store wywołuje usługę Product, aby uzyskać listę wszystkich bieżących produktów dostępnych do zakupu.

Bieżąca wersja aplikacji nie posiada mechanizmów odpornościowych. Jeśli usługa Product jest niedostępna, usługa Store zwraca błąd do klientów i prosi ich o ponowną próbę później. To zachowanie nie jest dobrym doświadczeniem użytkownika.

Menedżer prosi Cię o dodanie odporności do aplikacji, aby usługa Store ponawiała próbę wywołania usługi zaplecza w przypadku niepowodzenia.

W tym ćwiczeniu dodasz odporność do istniejącej aplikacji natywnej dla chmury i przetestujesz poprawkę.

Otwieranie środowiska projektowego

Możesz użyć przestrzeni kodu usługi GitHub, która hostuje ćwiczenie, lub wykonać ćwiczenie lokalnie w programie Visual Studio Code.

Aby użyć przestrzeni kodu, utwórz wstępnie skonfigurowaną przestrzeń GitHub Codespace, korzystając z tego linku do tworzenia przestrzeni.

Utworzenie i skonfigurowanie przestrzeni kodu w usłudze GitHub trwa kilka minut. Po zakończeniu procesu zobaczysz pliki kodu dla ćwiczenia. Kod do użycia w pozostałej części tego modułu znajduje się w katalogu /dotnet-resiliency .

Aby użyć programu Visual Studio Code, sklonuj https://github.com/MicrosoftDocs/mslearn-dotnet-cloudnative repozytorium na komputer lokalny. Wtedy:

  1. Zainstaluj wszystkie wymagania systemowe , aby uruchomić kontener deweloperski w programie Visual Studio Code.
  2. Upewnij się, że platforma Docker jest uruchomiona.
  3. W nowym oknie programu Visual Studio Code otwórz folder sklonowanego repozytorium
  4. Naciśnij Ctrl+Shift+P , aby otworzyć paletę poleceń.
  5. Wyszukiwanie: >Kontenery deweloperskie: Odbuduj i otwórz ponownie w kontenerze
  6. Wybierz pozycję eShopLite — dotnet-resiliency z listy rozwijanej. Program Visual Studio Code tworzy kontener programistyczny lokalnie.

Kompilowanie i uruchamianie aplikacji

  1. W dolnym panelu wybierz kartę TERMINAL i uruchom następujące polecenie, aby przejść do katalogu głównego kodu:

    cd dotnet-resiliency
    
  2. Uruchom następujące polecenie, aby skompilować obrazy aplikacji eShop:

    dotnet publish /p:PublishProfile=DefaultContainer
    
  3. Po zakończeniu kompilacji uruchom następujące polecenie, aby uruchomić aplikację:

    docker compose up
    
  4. W dolnym panelu wybierz kartę PORTY, a następnie w kolumnie Adres przekazany w tabeli wybierz ikonę Otwórz w przeglądarce dla portu Front End (32000).

    Jeśli używasz aplikacji lokalnie, otwórz okno przeglądarki, aby wyświetlić http://localhost:32000/products.

  5. Aplikacja eShop powinna być uruchomiona. Wybierz element menu Produkty . Powinna zostać wyświetlona lista produktów.

    Zrzut ekranu przedstawiający aplikację eShop działającą w przeglądarce.

Testowanie bieżącej odporności

Zatrzymaj usługę produktu, aby zobaczyć, co się stanie z aplikacją.

  1. Wróć do przestrzeni kodu, a na karcie TERMINAL wybierz pozycję +, aby otworzyć nowy terminal bash.

  2. Uruchom następujące polecenie platformy Docker, aby wyświetlić listę uruchomionych kontenerów:

    docker ps
    

    Powinna zostać wyświetlona lista aktualnie uruchomionych kontenerów, na przykład:

    CONTAINER ID   IMAGE                                                                            COMMAND                  CREATED          STATUS          PORTS                                                        NAMES
    c08285e8aaa4   storeimage                                                                       "dotnet Store.dll"       8 minutes ago    Up 8 minutes    80/tcp, 443/tcp, 0.0.0.0:5902->8080/tcp, :::5902->8080/tcp   eshoplite-frontend-1
    6ba80f3c7ab0   productservice                                                                   "dotnet Products.dll"    8 minutes ago    Up 8 minutes    80/tcp, 443/tcp, 0.0.0.0:5200->8080/tcp, :::5200->8080/tcp   eshoplite-backend-1
    cd0c822a5222   vsc-eshoplite-958868d22c9851dd911b2423199bfc782861d1a8f7afac48e5096a1b7516082f   "/bin/sh -c 'echo Co…"   27 minutes ago   Up 27 minutes     
    
  3. Wyszukaj identyfikator KONTENERa dla kontenera productservice . W powyższym przykładzie identyfikator to 6ba80f3c7ab0.

  4. Zatrzymaj usługę produktu za pomocą tego polecenia platformy Docker:

    docker stop <CONTAINER ID>
    

    Gdzie <CONTAINER ID> jest identyfikatorem znalezionym w poprzednim kroku. Na przykład:

    docker stop 6ba80f3c7ab0
    
  5. Wróć do karty przeglądarki z uruchomioną aplikacją i odśwież stronę. Powinien zostać wyświetlony komunikat o błędzie:

    Wystąpił problem podczas ładowania naszych produktów. Spróbuj ponownie później.

  6. Wróć do przestrzeni kodu, a w terminalu wybierz terminal platformy Docker i naciśnij Ctrl+C , aby zatrzymać aplikację. Powinieneś zobaczyć:

    Gracefully stopping... (press Ctrl+C again to force)
    Aborting on container exit...
    [+] Stopping 2/1
     ✔ Container eshoplite-frontend-1  Stopped                                                                      0.3s 
     ✔ Container eshoplite-backend-1   Stopped                                                                      0.0s 
    canceled
    

Dodawanie odporności do aplikacji

Pierwszymi krokami umożliwiającymi zwiększenie odporności aplikacji jest dodanie pakietu NuGet Microsoft.Extensions.Http.Resilience do projektu. Następnie można go użyć w Program.cs.

Dodaj pakiet Microsoft.Extensions.Http.Resilience

  1. W obszarze codespace w zakładce TERMINAL przejdź do folderu projektu Store :

    cd Store
    
  2. Uruchom następujące polecenie, aby dodać pakiet NuGet resiliency:

    dotnet add package Microsoft.Extensions.Http.Resilience
    

    Uruchomienie tego polecenia w terminalu w folderze projektu „apps” powoduje dodanie odwołania do pakietu do pliku projektu Store.csproj.

  3. Na pasku bocznym EKSPLORATORa wybierz pozycję Program.cs.

  4. W górnej części pliku dodaj następującą instrukcję using:

    using Microsoft.Extensions.Http.Resilience;
    

Dodawanie standardowej strategii odporności

  1. W wierszu 13 przed ;dodaj następujący kod:

    .AddStandardResilienceHandler()
    

    Kod powinien wyglądać następująco:

    builder.Services.AddHttpClient<ProductService>(c =>
    {
        var url = builder.Configuration["ProductEndpoint"] ?? throw new InvalidOperationException("ProductEndpoint is not set");
    
        c.BaseAddress = new(url);
    }).AddStandardResilienceHandler();
    

    Powyższy kod dodaje standardową procedurę obsługi rezyliencji do HTTPClient. Procedura obsługi używa wszystkich domyślnych ustawień standardowej strategii odporności.

    Do aplikacji nie są potrzebne żadne inne zmiany kodu. Uruchomimy aplikację i przetestujmy odporność.

  2. Uruchom następujące polecenia, aby ponownie skompilować aplikację eShop:

    cd ..
    dotnet publish /p:PublishProfile=DefaultContainer
    
  3. Po zakończeniu kompilacji uruchom następujące polecenie, aby uruchomić aplikację:

    docker compose up
    
  4. Wróć do karty przeglądarki z uruchomioną aplikacją i odśwież stronę produktu. Powinna zostać wyświetlona lista produktów.

  5. Wróć do swojej przestrzeni kodu i na karcie TERMINAL wybierz drugi terminal Bash. Skopiuj identyfikator KONTENERa dla kontenera productservice .

  6. Uruchom ponownie polecenie docker stop:

    docker stop <CONTAINER ID>
    
  7. Wróć do karty przeglądarki z uruchomioną aplikacją i odśwież stronę produktu. Tym razem powinno upłynąć nieco dłużej, dopóki nie zostanie wyświetlony komunikat o błędzie aplikacji:

    Wystąpił problem podczas ładowania naszych produktów. Spróbuj ponownie później.

    Sprawdźmy dzienniki, aby sprawdzić, czy nasza strategia odporności działa.

  8. Wróć do przestrzeni kodu, a na karcie TERMINAL wybierz terminal platformy Docker .

  9. W terminalu naciśnij Ctrl+C , aby zatrzymać działanie aplikacji.

  10. W komunikatach dziennika przewiń w górę, aż natrafisz na odwołania do Polly.

    eshoplite-frontend-1  | warn: Polly[3]
    eshoplite-frontend-1  |       Execution attempt. Source: 'ProductService-standard//Standard-Retry', Operation Key: '', Result: 'Name or service not known (backend:8080)', Handled: 'True', Attempt: '2', Execution Time: '27.2703'
    

    Powinien zostać wyświetlonych wiele takich komunikatów; każda z nich to próba ponawiania próby. Powyższy komunikat pokazuje drugą próbę i czas wykonania.

Konfigurowanie strategii odporności

Gdy dodasz odporność do aplikacji, równoważysz potrzebę szybkiego reagowania na użytkowników, a konieczność nie przeciążenia żadnych usług zaplecza. Tylko ty możesz zdecydować, czy opcje domyślne spełniają Twoje potrzeby firmy.

W tym przykładzie chcesz, aby obsługa sklepu poczekała nieco dłużej, aby dać jej szansę na odbudowanie się.

  1. W oknie kodu dla Program.cs zmień kod w wierszu 13 na:

    .AddStandardResilienceHandler(options =>
    {
        options.Retry.MaxRetryAttempts = 7;
    });
    

    Powyższy kod zmienia domyślną strategię ponawiania prób, aby liczba powtórzeń była maksymalnie siedem razy. Pamiętaj, że strategia polega na wykładniczym zwiększaniu opóźnień, więc łączny czas wynosi około 5 minut.

  2. Zatrzymaj Docker za pomocą Ctrl+C. Następnie uruchom następujące polecenie, aby ponownie skompilować aplikację eShop:

    dotnet publish /p:PublishProfile=DefaultContainer
    
  3. Po zakończeniu kompilacji uruchom następujące polecenie, aby uruchomić aplikację:

    docker compose up
    

    Zatrzymaj kontener usługi backend w terminalu bash i odśwież eShop. Zwróć uwagę, że wyświetlenie komunikatu o błędzie trwa dłużej. Jeśli jednak sprawdzisz dzienniki, zobaczysz, że strategia ponawiania prób została ponowiona pięć razy. Ostatni komunikat z polly to:

    Polly.Timeout.TimeoutRejectedException: The operation didn't complete within the allowed timeout of '00:00:30'.
    

    Powyższy komunikat informuje, że łączny limit czasu żądania uniemożliwia osiągnięcie maksymalnej liczby ponownych prób. Problem można rozwiązać, zwiększając łączny limit czasu żądania.

  4. W terminalu naciśnij Ctrl+C , aby zatrzymać aplikację.

  5. W oknie kodu dla Program.cs zmień kod w wierszu 13 na:

    .AddStandardResilienceHandler(options =>
    {
        options.Retry.RetryCount = 7;
        options.TotalRequestTimeout = new HttpTimeoutStrategyOptions
        {
            Timeout = TimeSpan.FromMinutes(5)
        };
    });
    

    Powyższy kod zmienia łączny limit czasu żądania na 260 sekund, co jest teraz dłuższe niż strategia ponawiania prób.

    Dzięki tym zmianom należy mieć wystarczająco dużo czasu, aby uruchomić aplikację, zatrzymać usługę produktu, sprawdzić dzienniki terminalu pod kątem ponownych prób, odświeżyć sklep eShop, aby wyświetlić komunikat ładowania, a następnie ponownie uruchomić usługę produktu, aby pomyślnie wyświetlić listę produktów.

  6. Uruchom następujące polecenie, aby ponownie skompilować aplikację eShop:

    dotnet publish /p:PublishProfile=DefaultContainer
    
  7. Po zakończeniu kompilacji uruchom następujące polecenie, aby uruchomić aplikację:

    docker compose up
    

Testowanie nowych opcji odporności

Aby ułatwić testowanie aplikacji w kontenerze, użyj rozszerzenia platformy Docker. Rozszerzenie udostępnia graficzny interfejs użytkownika do wyświetlania i kontrolowania stanu kontenerów.

  1. W menu po lewej stronie wybierz ikonę platformy Docker .

    Zrzut ekranu rozszerzenia platformy Docker przedstawiający sposób zatrzymywania usługi produktów.

  2. W panelu DOCKER w obszarze KONTENERY kliknij prawym przyciskiem myszy kontener products i wybierz pozycję Zatrzymaj.

  3. Wróć do karty przeglądarki z uruchomioną aplikacją i odśwież stronę produktu. Powinien zostać wyświetlony komunikat Trwa ładowanie...

  4. Wróć do przestrzeni kodu, a następnie na karcie TERMINAL wybierz terminal platformy Docker . Strategia odporności działa.

  5. W panelu DOCKER w obszarze KONTENERY kliknij prawym przyciskiem myszy kontener products i wybierz polecenie Uruchom.

  6. Wróć do karty przeglądarki z uruchomioną aplikacją. Poczekaj, a aplikacja powinna wyświetlić listę produktów.

  7. W terminalu zatrzymaj Docker za pomocą Ctrl+C.