연습 - 애플리케이션 복원력 구현

완료됨

eShop 프로젝트에는 HTTP 요청을 사용하여 서로 통신하는 두 개의 서비스가 있습니다. 서비스는 Store 서비스를 호출 Product 하여 구매할 수 있는 모든 현재 제품 목록을 가져옵니다.

앱의 현재 버전에는 복원력 처리가 없습니다. Product 서비스를 사용할 수 없는 Store 경우 서비스는 고객에게 오류를 반환하고 나중에 다시 시도하도록 요청합니다. 이 동작은 좋은 사용자 환경이 아닙니다.

관리자가 앱에 복원력을 추가하도록 요청하여 Store 서비스가 실패할 경우 백 엔드 서비스 호출을 다시 시도하도록 합니다.

이 연습에서는 기존 클라우드 네이티브 앱에 복원력을 추가하고 수정 사항을 테스트합니다.

개발 환경 열기

연습을 호스팅하는 GitHub 코드 공간을 사용하거나 Visual Studio Code에서 로컬로 연습을 완료하도록 선택할 수 있습니다.

codespace를 사용하려면 이 Codespace 만들기 링크를 사용하여 사전 구성된 GitHub Codespace를 만듭니다.

GitHub는 코드스페이스를 만들고 구성하는 데 몇 분 정도 걸립니다. 프로세스가 완료되면 연습에 대한 코드 파일이 표시됩니다. 이 모듈의 나머지 부분에 사용할 코드는 /dotnet-resiliency 디렉터리에 있습니다.

Visual Studio Code를 사용하려면 https://github.com/MicrosoftDocs/mslearn-dotnet-cloudnative 리포지토리를 로컬 컴퓨터에 복제합니다. 그러면:

  1. Visual Studio Code에서 Dev Container를 실행하려면 시스템 요구 사항을 설치합니다.
  2. Docker가 실행 중인지 확인합니다.
  3. 새 Visual Studio Code 창에서 복제된 리포지토리의 폴더를 엽니다.
  4. 명령 팔레트를 열려면 Ctrl+Shift+P를 누릅니다.
  5. 검색: >개발 컨테이너: 다시 빌드하고 컨테이너에서 다시 열기
  6. 드롭다운에서 eShopLite - dotnet-resiliency 를 선택합니다. Visual Studio Code는 개발 컨테이너를 로컬로 만듭니다.

앱 빌드 및 실행

  1. 아래쪽 패널에서 터미널 탭을 선택하고 다음 명령을 실행하여 코드 루트로 이동합니다.

    cd dotnet-resiliency
    
  2. 다음 명령을 실행하여 eShop 앱 이미지를 빌드합니다.

    dotnet publish /p:PublishProfile=DefaultContainer
    
  3. 빌드가 완료되면 다음 명령을 실행하여 앱을 시작합니다.

    docker compose up
    
  4. 아래쪽 패널에서 포트 탭을 선택한 다음 테이블의 전달된 주소 열에서 프런트 엔드(32000) 포트에 대한 브라우저에서 열기 아이콘을 선택합니다.

    앱을 로컬로 실행하는 경우 http://localhost:32000/products을(를) 보려면 브라우저 창을 여세요.

  5. eShop 앱이 실행 중이어야 합니다. 제품 메뉴 항목을 선택하면 제품 목록이 표시됩니다.

    브라우저에서 실행되는 eShop 앱을 보여 주는 스크린샷

현재의 복원력을 테스트하십시오

제품 서비스를 중지하여 앱에 어떤 일이 발생하는지 확인합니다.

  1. 코드 영역으로 돌아가서 터미널 탭에서 새 bash 터미널을 열려고 선택합니다 + .

  2. 다음 docker 명령을 실행하여 실행 중인 컨테이너를 나열합니다.

    docker ps
    

    예를 들어 현재 실행 중인 컨테이너 목록이 표시됩니다.

    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. productservice 컨테이너에 대한 컨테이너 ID를 찾습니다. 위의 예제에서 ID는 6ba80f3c7ab0입니다.

  4. 다음 docker 명령을 사용하여 제품 서비스를 중지합니다.

    docker stop <CONTAINER ID>
    

    <CONTAINER ID> 여기서 이전 단계에서 찾은 ID입니다. 다음은 그 예입니다.

    docker stop 6ba80f3c7ab0
    
  5. 앱을 실행하는 브라우저 탭으로 돌아가 페이지를 새로 고칩니다. 다음과 같은 오류 메시지가 표시됩니다.

    제품을 로드하는 데 문제가 있습니다. 나중에 다시 시도하세요.

  6. 코드스페이스로 돌아가 서 터미널 에서 Docker 터미널을 선택하고 Ctrl+C 를 눌러 앱을 중지합니다. 다음과 같은 결과가 표시됩니다.

    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
    

앱에 복원력 추가

앱의 복원력을 높이는 첫 번째 단계는 프로젝트에 NuGet 패키지를 추가하는 Microsoft.Extensions.Http.Resilience 것입니다. 그런 다음 Program.cs 사용할 수 있습니다.

Microsoft.Extensions.Http.Resilience 패키지 추가

  1. 코드스페이스의 터미널 탭에서 스토어 프로젝트 폴더로 이동합니다.

    cd Store
    
  2. 다음 명령을 실행하여 복원력 NuGet 패키지를 추가합니다.

    dotnet add package Microsoft.Extensions.Http.Resilience
    

    앱 프로젝트 폴더의 터미널에서 이 명령을 실행하면 패키지 참조가 Store.csproj 프로젝트 파일에 추가됩니다.

  3. 탐색기 사이드바에서 Program.cs 선택합니다.

  4. 파일 맨 위에 다음 using 문을 추가합니다.

    using Microsoft.Extensions.Http.Resilience;
    

표준 복원력 전략 추가

  1. 이전의 줄 13에서 다음 코드를 추가합니다.

    .AddStandardResilienceHandler()
    

    코드는 다음과 비슷합니다.

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

    위의 코드는 HTTPClient에 표준 복원력 처리기를 추가합니다. 처리기는 표준 복원력 전략에 대한 모든 기본 설정을 사용합니다.

    앱에 다른 코드 변경이 필요하지 않습니다. 앱을 실행하고 복원력을 테스트해 보겠습니다.

  2. 다음 명령을 실행하여 eShop 앱을 다시 빌드합니다.

    cd ..
    dotnet publish /p:PublishProfile=DefaultContainer
    
  3. 빌드가 완료되면 다음 명령을 실행하여 앱을 시작합니다.

    docker compose up
    
  4. 앱을 실행하는 브라우저 탭으로 돌아가 제품 페이지를 새로 고칩니다. 제품 목록이 표시됩니다.

  5. 코드스페이스로 돌아가 터미널 탭에서 두 번째 bash 터미널을 선택합니다. productservice 컨테이너의 CONTAINER ID를 복사합니다.

  6. docker stop 명령을 다시 실행합니다.

    docker stop <CONTAINER ID>
    
  7. 앱을 실행하는 브라우저 탭으로 돌아가 제품 페이지를 새로 고칩니다. 이번에는 앱 오류 메시지가 표시될 때까지 시간이 좀 더 오래 걸립니다.

    제품을 로드하는 데 문제가 있습니다. 나중에 다시 시도하세요.

    로그를 확인하여 복원력 전략이 작동하는지 확인해 보겠습니다.

  8. 코드스페이스로 돌아가 터미널 탭에서 Docker 터미널을 선택합니다.

  9. 터미널에서 Ctrl+C 를 눌러 앱 실행을 중지합니다.

  10. 로그 메시지에서 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'
    

    다음과 같은 메시지가 많이 표시됩니다. 각각은 재시도 시도입니다. 위의 메시지는 두 번째 시도와 실행하는 데 걸린 시간을 보여줍니다.

복원력 전략 구성

앱에 복원력을 추가할 때 백 엔드 서비스를 오버로드하지 않아도 되므로 사용자에게 신속하게 응답해야 하는 필요성의 균형을 맞추게 됩니다. 기본 옵션이 비즈니스 요구 사항을 충족하는지 여부만 결정할 수 있습니다.

이 예제에서는 스토어 서비스를 복구할 수 있는 기회를 제공하기 위해 스토어 서비스가 좀 더 오래 기다리도록 합니다.

  1. Program.cs 대한 코드 창에서 13줄의 코드를 다음으로 변경합니다.

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

    위의 코드는 재시도 전략 기본값을 최대 사용 중지 횟수를 7개로 변경합니다. 전략은 지수 백오프이므로 총 시간은 약 5분입니다.

  2. Ctrl+ C를 사용하여 Docker를 중지합니다. 그런 다음, 다음 명령을 실행하여 eShop 앱을 다시 빌드합니다.

    dotnet publish /p:PublishProfile=DefaultContainer
    
  3. 빌드가 완료되면 다음 명령을 실행하여 앱을 시작합니다.

    docker compose up
    

    bash 터미널에서 백 엔드 서비스 컨테이너를 중지하고 eShop을 새로 고칩니다. 오류 메시지를 보는 데 시간이 더 오래 걸립니다. 하지만 로그를 확인하면 재시도 전략이 5번만 다시 시도되었음을 알 수 있습니다. Polly의 마지막 메시지는 다음과 같습니다.

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

    위의 메시지는 총 요청 시간 제한이 최대 재시도 횟수에 도달하지 못하도록 중지한다는 것을 알려줍니다. 총 요청 시간 제한을 늘려 문제를 해결할 수 있습니다.

  4. 터미널에서 Ctrl+C 를 눌러 앱을 중지합니다.

  5. Program.cs 대한 코드 창에서 13줄의 코드를 다음으로 변경합니다.

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

    위의 코드는 총 요청 시간 제한을 260초로 변경하여 다시 시도 전략보다 더 깁니다.

    이러한 변경 내용에 따라, 앱을 실행하고 제품 서비스를 중지한 후 터미널 로그에서 재시도 시도를 확인하십시오. 그 다음 eShop을 새로 고쳐 로드 메시지를 확인한 후, 마지막으로 제품 서비스를 다시 시작하여 성공적으로 제품 목록을 확인할 수 있습니다.

  6. 다음 명령을 실행하여 eShop 앱을 다시 빌드합니다.

    dotnet publish /p:PublishProfile=DefaultContainer
    
  7. 빌드가 완료되면 다음 명령을 실행하여 앱을 시작합니다.

    docker compose up
    

새 복원력 옵션 테스트

컨테이너에서 앱을 테스트하는 데 도움이 되도록 Docker 확장을 사용합니다. 확장은 컨테이너의 상태를 보고 제어하는 GUI를 제공합니다.

  1. 왼쪽 메뉴에서 Docker 아이콘을 선택합니다.

    제품 서비스를 중지하는 방법을 보여 주는 Docker 확장의 스크린샷

  2. DOCKER 패널의 CONTAINERS 아래에서 제품 컨테이너를 마우스 오른쪽 단추로 클릭하고 중지를 선택합니다.

  3. 앱을 실행하는 브라우저 탭으로 돌아가 제품 페이지를 새로 고칩니다. 로드 중... 메시지가 표시됩니다.

  4. 코드스페이스로 돌아가 터미널 탭에서 Docker 터미널을 선택합니다. 복원력 전략이 작동합니다.

  5. DOCKER 패널의 CONTAINERS 아래에서 제품 컨테이너를 마우스 오른쪽 단추로 클릭하고 시작을 선택합니다.

  6. 앱을 실행하는 브라우저 탭으로 돌아갑니다. 기다리면 앱이 제품 목록을 표시하며 복구될 것입니다.

  7. 터미널에서 CtrlC를 사용하여 docker를 + 중지합니다.