연습 - 애플리케이션 복원력 구현
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 리포지토리를 로컬 컴퓨터에 복제합니다. 다음 작업:
- Visual Studio Code에서 Dev Container를 실행하려면 시스템 요구 사항을 설치합니다.
- Docker가 실행 중인지 확인합니다.
- 새 Visual Studio Code 창에서 복제된 리포지토리의 폴더를 엽니다.
- 명령 팔레트를 열려면 Ctrl+Shift+P를 누릅니다.
- 검색: >개발 컨테이너: 다시 빌드 및 컨테이너에서 다시 열기
- 드롭다운에서 eShopLite - dotnet-resiliency를 선택합니다. Visual Studio Code가 개발 컨테이너를 로컬로 만듭니다.
앱 빌드 및 실행
아래쪽 패널에서 터미널 탭을 선택하고 다음 명령을 실행하여 코드 루트로 이동합니다.
cd dotnet-resiliency
다음 명령을 실행하여 eShop 앱 이미지를 빌드합니다.
dotnet publish /p:PublishProfile=DefaultContainer
빌드가 완료되면 다음 명령을 실행하여 앱을 시작합니다.
docker compose up
아래쪽 패널에서 포트 탭을 선택한 다음 테이블의 전달된 주소 열에서 프런트 엔드(32000) 포트에 대한 브라우저에서 열기 아이콘을 선택합니다.
앱을 로컬로 실행하는 경우 브라우저 창을 열어
http://localhost:32000/products
을(를) 확인합니다.eShop 앱이 실행 중이어야 합니다. 제품 메뉴 항목을 선택하면 제품 목록이 표시됩니다.
현재 복원력 테스트
제품 서비스를 중지하여 앱에 어떤 일이 발생하는지 확인합니다.
codespace로 돌아가서 터미널 탭에서 +를 선택하여 새 bash 터미널을 엽니다.
다음 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
productservice 컨테이너에 대한 컨테이너 ID를 찾습니다. 위의 예제에서 ID는 6ba80f3c7ab0입니다.
다음 docker 명령을 사용하여 제품 서비스를 중지합니다.
docker stop <CONTAINER ID>
여기서
<CONTAINER ID>
는 이전 단계에서 찾은 ID입니다. 예시:docker stop 6ba80f3c7ab0
앱이 실행 중인 브라우저로 돌아가 페이지를 새로 고칩니다. 오류 메시지가 표시되어야 합니다.
제품을 로드하는 데 문제가 있습니다. 나중에 다시 시도하세요.
codespace로 돌아가 터미널에서 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
앱에 복원력 추가
앱의 복원력을 높이는 첫 번째 단계는 프로젝트에 Microsoft.Extensions.Http.Resilience
NuGet 패키지를 추가하는 것입니다. 그런 다음 Program.cs에서 사용할 수 있습니다.
Microsoft.Extensions.Http.Resilience 패키지 추가
codespace의 터미널 탭에서 스토어 프로젝트 폴더로 이동합니다.
cd Store
다음 명령을 실행하여 복원력 NuGet 패키지를 추가합니다.
dotnet add package Microsoft.Extensions.Http.Resilience
앱 프로젝트 폴더의 터미널에서 이 명령을 실행하면 Store.csproj 프로젝트 파일에 패키지 참조가 추가됩니다.
EXPLORER 사이드바에서 Program.cs를 선택합니다.
파일 맨 위에 다음 using 문을 추가합니다.
using Microsoft.Extensions.Http.Resilience;
표준 복원력 전략 추가
줄 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에 표준 복원력 처리기를 추가합니다. 처리기는 표준 복원력 전략에 대한 모든 기본 설정을 사용합니다.
앱에 다른 코드 변경은 필요하지 않습니다. 앱을 실행하고 복원력을 테스트해 보겠습니다.
다음 명령을 실행하여 eShop 앱을 다시 빌드합니다.
cd .. dotnet publish /p:PublishProfile=DefaultContainer
빌드가 완료되면 다음 명령을 실행하여 앱을 시작합니다.
docker compose up
앱이 실행 중인 브라우저로 돌아가 제품 페이지를 새로 고칩니다. 제품 목록이 표시되어야 합니다.
codespace로 돌아가서 터미널 탭에서 두 번째 bash 터미널을 선택합니다. productservice 컨테이너에 대한 컨테이너 ID를 복사합니다.
Docker stop 명령을 다시 실행합니다.
docker stop <CONTAINER ID>
앱이 실행 중인 브라우저로 돌아가 제품 페이지를 새로 고칩니다. 이번에는 앱 오류 메시지가 표시될 때까지 시간이 좀 더 오래 걸립니다.
제품을 로드하는 데 문제가 있습니다. 나중에 다시 시도하세요.
검사 복원력 전략이 작동하는지 여부를 파악하기 위해 로그를 확인해 보겠습니다.
codespace로 돌아가서 터미널 탭에서 docker 터미널을 선택합니다.
터미널에서 Ctrl+C를 눌러 앱 실행을 중지합니다.
로그 메시지에서 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'
다음과 같은 많은 메시지가 표시되며, 각 메시지가 다시 시도를 나타냅니다. 위의 메시지는 두 번째 시도와 실행하는 데 걸린 시간을 보여 줍니다.
복원력 전략 구성
앱에 복원력을 추가할 때 백 엔드 서비스를 오버로드하지 않아도 되므로 사용자에게 신속하게 응답해야 하는 필요성의 균형을 맞추게 됩니다. 기본 옵션이 비즈니스 요구 사항을 충족하는지 여부만 결정할 수 있습니다.
이 예제에서는 스토어 서비스를 복구할 수 있는 기회를 제공하기 위해 스토어 서비스가 좀 더 오래 기다리도록 합니다.
Program.cs의 코드 창에서 줄 13의 코드를 다음으로 변경합니다.
.AddStandardResilienceHandler(options => { options.Retry.MaxRetryAttempts = 7; });
위의 코드는 재시도 전략 기본값의 최대 재시도 횟수를 7로 변경합니다. 전략은 지수 백오프이므로 총 시간은 약 5분입니다.
Ctrl+C를 사용하여 Docker를 중지합니다. 그런 다음 아래 명령을 실행하여 eShop 앱을 다시 빌드합니다.
dotnet publish /p:PublishProfile=DefaultContainer
빌드가 완료되면 다음 명령을 실행하여 앱을 시작합니다.
docker compose up
bash 터미널에서 백 엔드 서비스 컨테이너를 중지하고 eShop을 새로 고칩니다. 오류 메시지를 보는 데는 시간이 더 오래 걸립니다. 로그를 확인하면 다시 시도 전략이 5번만 다시 시도되었음을 알 수 있습니다. Polly의 마지막 메시지는 다음과 같습니다.
Polly.Timeout.TimeoutRejectedException: The operation didn't complete within the allowed timeout of '00:00:30'.
위의 메시지는 총 요청 시간 제한으로 인해 최대 다시 시도 횟수에 도달하지 못했음을 알려줍니다. 총 요청 시간 제한을 늘려 이 문제를 해결할 수 있습니다.
터미널에서 Ctrl+C를 눌러 앱을 중지합니다.
Program.cs의 코드 창에서 줄 13의 코드를 다음으로 변경합니다.
.AddStandardResilienceHandler(options => { options.Retry.RetryCount = 7; options.TotalRequestTimeout = new HttpTimeoutStrategyOptions { Timeout = TimeSpan.FromMinutes(5) }; });
위의 코드는 총 요청 시간 제한을 260초로 변경하는데, 이는 재시도 전략보다 긴 수치입니다.
이러한 변경을 적용하여 앱을 실행하고, 제품 서비스를 중지하고, 다시 시도를 위해 터미널 로그를 검사하고, eShop을 새로 고쳐 로드 메시지를 확인하고, 마지막으로 제품 서비스를 다시 시작하여 제품 목록을 성공적으로 확인할 수 있는 충분한 시간이 확보됩니다.
다음 명령을 실행하여 eShop 앱을 다시 빌드합니다.
dotnet publish /p:PublishProfile=DefaultContainer
빌드가 완료되면 다음 명령을 실행하여 앱을 시작합니다.
docker compose up
새 복원력 옵션 테스트
컨테이너에서 앱을 테스트하는 데 도움이 되도록 Docker 확장을 사용합니다. 확장은 컨테이너 상태를 보고 제어할 수 있는 GUI를 제공합니다.
왼쪽 메뉴에서 Docker 아이콘을 선택합니다.
DOCKER 패널의 컨테이너에서 products 컨테이너를 마우스 오른쪽 단추로 클릭하고 중지를 선택합니다.
앱이 실행 중인 브라우저로 돌아가 제품 페이지를 새로 고칩니다. 로드 중... 메시지가 표시됩니다.
codespace로 돌아가 터미널 탭에서 docker 터미널을 선택합니다. 복원력 전략이 작동합니다.
DOCKER 패널의 컨테이너에서 products 컨테이너를 마우스 오른쪽 단추로 클릭하고 시작을 선택합니다.
앱을 실행하는 브라우저 탭으로 돌아갑니다. 기다리면 앱이 복구되어 제품 목록이 표시됩니다.
터미널에서 Ctrl+C를 사용하여 docker를 중지합니다.