편집

다음을 통해 공유


.NET에 대한 신뢰할 수 있는 웹앱 패턴

Azure App Service
Azure Front Door
Azure Cache for Redis
.NET

이 문서에서는 신뢰할 수 있는 웹앱 패턴을 구현하는 방법에 대한 지침을 제공합니다. 이 패턴은 클라우드 마이그레이션을 위해 웹앱을 수정(다시 배치)하는 방법을 간략하게 설명합니다. 잘 설계된 프레임워크원칙에 부합하는 규범적 아키텍처, 코드 및 구성 지침을 제공합니다.

.NET에 대한 신뢰할 수 있는 웹앱 패턴인 이유는 무엇인가요?

신뢰할 수 있는 웹앱 패턴은 클라우드로 마이그레이션할 때 웹앱을 다시 배치하는 방법을 정의하는 일련의 원칙 및 구현 기술입니다. 클라우드에서 성공하기 위해 수행해야 하는 최소한의 코드 업데이트에 중점을 둡니다. 다음 지침에서는 참조 구현을 예제로 사용하고 가상의 회사인 Relecloud의 재배치 과정을 따라 여정에 대한 비즈니스 컨텍스트를 제공합니다. .NET용 Reliable Web App 패턴을 구현하기 전에 Relecloud에는 ASP.NET 프레임워크를 사용하는 모놀리식 온-프레미스 티켓 웹앱이 있었습니다.

GitHub 로고 신뢰할 수 있는 웹앱 패턴의 참조 구현 (샘플)이 있습니다. Relecloud라는 가상 회사에 대한 신뢰할 수 있는 웹앱 구현의 최종 상태를 나타냅니다. 이 문서에서 설명하는 모든 코드, 아키텍처 및 구성 업데이트를 제공하는 프로덕션 수준의 웹앱입니다. 참조 구현을 배포하고 사용하여 신뢰할 수 있는 웹앱 패턴의 구현을 안내합니다.

신뢰할 수 있는 웹앱 패턴을 구현하는 방법

이 문서에는 신뢰할 수 있는 웹앱 패턴을 구현하기 위한 아키텍처, 코드 및 구성 지침이 포함되어 있습니다. 다음 링크를 사용하여 필요한 특정 지침으로 이동합니다.

  • 비즈니스 컨텍스트: 이 지침을 비즈니스 컨텍스트에 맞게 조정하고 재편성 결정을 유도하는 즉각적이고 장기적인 목표를 정의하는 방법을 알아봅니다.
  • 아키텍처 지침: 올바른 클라우드 서비스를 선택하고 비즈니스 요구 사항을 충족하는 아키텍처를 디자인하는 방법을 알아봅니다.
  • 코드 지침: 클라우드에서 웹앱의 안정성과 성능 효율성을 개선하기 위한 세 가지 디자인 패턴 구현: 다시 시도, 회로 차단기 및 캐시 배제 패턴
  • 구성 지침: 인증 및 권한 부여, 관리 ID, 권한 있는 환경, 코드로서의 인프라 및 모니터링을 구성합니다.

비즈니스 컨텍스트

웹앱을 다시 배치하는 첫 번째 단계는 비즈니스 목표를 정의하는 것입니다. 서비스 수준 목표 및 비용 최적화 목표와 같은 즉각적인 목표와 웹 애플리케이션에 대한 향후 목표를 설정해야 합니다. 이러한 목표는 클라우드 서비스 선택 및 클라우드의 웹 애플리케이션 아키텍처에 영향을 줍니다. 99.9% 가동 시간 등 웹앱에 대한 대상 SLO를 정의합니다. 웹앱의 가용성에 영향을 주는 모든 서비스에 대한 복합 SLA 를 계산합니다.

예를 들어 Relecloud는 긍정적인 판매 예측을 가지고 있으며 티켓 웹앱에 대한 수요 증가를 예상합니다. 이러한 요구를 충족하기 위해 웹 애플리케이션에 대한 목표를 정의했습니다.

  • 저렴한 고가용성 코드 변경 적용
  • 99.9%의 SLO(서비스 수준 목표)에 도달
  • DevOps 사례 채택
  • 비용 최적화 환경 만들기
  • 안정성 및 보안 향상

Relecloud의 온-프레미스 인프라는 이러한 목표를 달성하기 위한 비용 효율적인 솔루션이 아니었습니다. 따라서 웹 애플리케이션을 Azure로 마이그레이션하는 것이 즉각적이고 미래의 목표를 달성하는 가장 비용 효율적인 방법이라고 결정했습니다.

아키텍처 지침

신뢰할 수 있는 웹앱 패턴에는 몇 가지 필수 아키텍처 요소가 있습니다. 엔드포인트 확인을 관리하는 DNS, 악의적인 HTTP 트래픽을 차단하는 웹 애플리케이션 방화벽 및 인바운드 사용자 요청을 보호하고 라우팅하는 부하 분산 장치가 필요합니다. 애플리케이션 플랫폼은 웹앱 코드를 호스트하고 가상 네트워크의 프라이빗 엔드포인트를 통해 모든 백 엔드 서비스를 호출합니다. 애플리케이션 성능 모니터링 도구는 메트릭 및 로그를 캡처하여 웹앱을 이해합니다.

신뢰할 수 있는 웹앱 패턴의 필수 아키텍처 요소를 보여 주는 다이어그램

그림 1 신뢰할 수 있는 웹앱 패턴의 필수 아키텍처 요소입니다.

아키텍처 설계

RTO(복구 시간 목표) 및 RPO(복구 지점 목표)와 같은 복구 메트릭을 지원하도록 인프라를 디자인합니다. RTO는 가용성에 영향을 미치며 SLO를 지원해야 합니다. RPO(복구 지점 목표)를 결정하고 RPO를 충족하도록 데이터 중복성을 구성합니다.

  • 인프라 안정성을 선택합니다. 가용성 요구 사항을 충족하는 데 필요한 가용성 영역 및 지역 수를 결정합니다. 복합 SLA가 SLO를 충족할 때까지 가용성 영역 및 지역을 추가합니다. Reliable Web App 패턴은 활성-활성 또는 활성-수동 구성에 대해 여러 지역을 지원합니다. 예를 들어 참조 구현은 활성-수동 구성을 사용하여 99.9%의 SLO를 충족합니다.

    다중 지역 웹앱의 경우 비즈니스 요구 사항에 따라 활성-활성 또는 활성-수동 구성을 지원하도록 트래픽을 두 번째 지역으로 라우팅하도록 부하 분산 장치를 구성합니다. 두 지역에는 한 지역에 지역을 연결하는 허브 가상 네트워크가 있다는 점을 제외하고 동일한 서비스가 필요합니다. 허브 및 스포크 네트워크 토폴로지 채택을 통해 네트워크 방화벽과 같은 리소스를 중앙 집중화하고 공유합니다. 가상 머신이 있는 경우 허브 가상 네트워크에 요새 호스트를 추가하여 안전하게 관리합니다(그림 2 참조).

    두 번째 지역 및 허브 및 스포크 토폴로지와 신뢰할 수 있는 웹앱 패턴을 보여 주는 다이어그램

    그림 2. 두 번째 지역 및 허브 및 스포크 토폴로지의 신뢰할 수 있는 웹앱 패턴입니다.

  • 네트워크 토폴로지 선택 웹 및 네트워킹 요구 사항에 적합한 네트워크 토폴로지 선택 여러 가상 네트워크를 사용하려는 경우 허브 및 스포크 네트워크 토폴로 지를 사용합니다. 온-프레미스 및 가상 네트워크에 대한 하이브리드 연결 옵션을 통해 비용, 관리 및 보안 이점을 제공합니다.

올바른 Azure 서비스 선택

웹앱을 클라우드로 이동하는 경우 비즈니스 요구 사항을 충족하고 온-프레미스 웹앱의 현재 기능에 부합하는 Azure 서비스를 선택해야 합니다. 맞춤은 재배치 작업을 최소화하는 데 도움이 됩니다. 예를 들어 동일한 데이터베이스 엔진을 유지하고 기존 미들웨어 및 프레임워크를 지원할 수 있는 서비스를 사용합니다. 다음 섹션에서는 웹앱에 적합한 Azure 서비스를 선택하기 위한 지침을 제공합니다.

예를 들어 클라우드로 이동하기 전에 Relecloud의 티켓 웹앱은 온-프레미스, 모놀리식 ASP.NET 앱이었습니다. 두 가상 머신에서 실행되었으며 Microsoft SQL Server 데이터베이스가 있었습니다. 웹앱은 확장성 및 기능 배포에서 일반적인 문제를 겪었습니다. 이 시작점, 비즈니스 목표 및 SLO는 서비스 선택을 이끌었습니다.

  • 애플리케이션 플랫폼: Azure 앱 Service를 애플리케이션 플랫폼으로 사용합니다. Relecloud는 다음과 같은 이유로 Azure 앱 서비스를 애플리케이션 플랫폼으로 선택했습니다.

    • 높은 SLA(서비스 수준 계약): 99.9%의 프로덕션 환경 SLO를 충족하는 높은 SLA를 가지고 있습니다.
    • 관리 오버헤드 감소: 크기 조정, 상태 검사 및 부하 분산을 처리하는 완전 관리형 솔루션입니다.
    • .NET 지원: 애플리케이션이 작성된 .NET 버전을 지원합니다.
    • 컨테이너화 기능: 웹앱은 컨테이너화 없이 클라우드에 수렴할 수 있지만 애플리케이션 플랫폼은 Azure 서비스를 변경하지 않고도 컨테이너화를 지원합니다.
    • 자동 크기 조정: 웹앱은 사용자 트래픽 및 구성 설정에 따라 자동으로 스케일 인 및 스케일 아웃할 수 있습니다. 또한 플랫폼은 다양한 호스팅 요구 사항을 수용하도록 확장 또는 축소를 지원합니다.
  • ID 관리: ID 및 액세스 관리 솔루션으로 Microsoft Entra ID를 사용합니다. Relecloud는 다음과 같은 이유로 Microsoft Entra ID를 선택했습니다.

    • 인증 및 권한 부여: 애플리케이션은 콜 센터 직원을 인증하고 권한을 부여해야 합니다.
    • 확장 가능: 더 큰 시나리오를 지원하도록 확장됩니다.
    • 사용자 ID 제어: 콜 센터 직원은 기존 엔터프라이즈 ID를 사용할 수 있습니다.
    • 권한 부여 프로토콜 지원: 관리 ID에 대해 OAuth 2.0을 지원합니다.
  • 데이터베이스: 동일한 데이터베이스 엔진을 유지할 수 있는 서비스를 사용합니다. 데이터 저장소 의사 결정 트리사용합니다. Relecloud의 웹앱은 SQL Server 온-프레미스를 사용했습니다. 따라서 기존 데이터베이스 스키마, 저장 프로시저 및 함수를 사용하려고 했습니다. 여러 SQL 제품은 Azure에서 사용할 수 있지만 Relecloud는 다음과 같은 이유로 Azure SQL Database를 선택했습니다.

    • 안정성: 범용 계층은 높은 SLA 및 다중 지역 중복성을 제공합니다. 높은 사용자 부하를 지원할 수 있습니다.
    • 관리 오버헤드 감소: 관리되는 SQL 데이터베이스 인스턴스를 제공합니다.
    • 마이그레이션 지원: 온-프레미스 SQL Server에서 데이터베이스 마이그레이션을 지원합니다.
    • 온-프레미스 구성과의 일관성: 기존 저장 프로시저, 함수 및 뷰를 지원합니다.
    • 복원력: 백업 및 지정 시간 복원을 지원합니다.
    • 전문 지식 및 최소한의 재작업: SQL Database는 사내 전문 지식을 활용하며 채택하려면 최소한의 작업이 필요합니다.
  • 애플리케이션 성능 모니터링: Application Insights를 사용하여 애플리케이션에서 원격 분석을 분석합니다. Relecloud는 다음과 같은 이유로 Application Insights를 사용하도록 선택했습니다.

    • Azure Monitor와의 통합: Azure Monitor와 최상의 통합을 제공합니다.
    • 변칙 검색: 성능 변칙을 자동으로 검색합니다.
    • 문제 해결: 실행 중인 앱에서 문제를 진단하는 데 도움이 됩니다.
    • 모니터링: 사용자가 앱을 사용하는 방법에 대한 정보를 수집하여 사용자 지정 이벤트를 쉽게 추적할 수 있습니다.
    • 가시성 격차: 온-프레미스 솔루션에 애플리케이션 성능 모니터링 솔루션이 없습니다. Application Insights는 애플리케이션 플랫폼 및 코드와 쉽게 통합할 수 있습니다.
  • 캐시: 웹앱 아키텍처에 캐시를 추가할지 여부를 선택합니다. Azure Cache for Redis 는 Azure의 기본 캐시 솔루션입니다. Redis 소프트웨어를 기반으로 하는 관리되는 메모리 내 데이터 저장소입니다. Relecloud의 웹앱 로드는 콘서트 및 장소 세부 정보를 보는 쪽으로 크게 기울어져 있으며 다음과 같은 이유로 Azure Cache for Redis를 추가했습니다.

    • 관리 오버헤드 감소: 완전 관리형 서비스입니다.
    • 속도 및 볼륨: 일반적으로 액세스되고 느린 변경 데이터에 대한 높은 데이터 처리량과 짧은 대기 시간 읽기가 있습니다.
    • 다양한 지원 가능성: 웹앱의 모든 인스턴스에서 사용할 수 있는 통합 캐시 위치입니다.
    • 외부 데이터 저장소: 온-프레미스 애플리케이션 서버에서 VM 로컬 캐싱을 수행했습니다. 이 설정은 자주 사용한 데이터를 오프로드하지 않았으며 데이터를 무효화할 수 없었습니다.
    • 비스틱 세션: 세션 상태를 외부화하면 비스틱 세션이 지원됩니다.
  • 부하 분산 장치: PaaS 솔루션을 사용하는 웹 애플리케이션은 Azure Front Door, Azure 애플리케이션 Gateway 또는 웹앱 아키텍처 및 요구 사항에 따라 둘 다 사용해야 합니다. 부하 분산 장치 의사 결정 트리를 사용하여 올바른 부하 분산 장치를 선택합니다. Relecloud에는 여러 지역에 걸쳐 트래픽을 라우팅할 수 있는 계층 7 부하 분산 장치가 필요했습니다. Relecloud는 99.9%의 SLO를 충족하기 위해 다중 지역 웹앱이 필요했습니다. Relecloud는 다음과 같은 이유로 Azure Front Door를 선택했습니다.

    • 전역 부하 분산: 여러 지역에 걸쳐 트래픽을 라우팅할 수 있는 계층 7 부하 분산 장치입니다.
    • 웹 애플리케이션 방화벽: 기본적으로 Azure 웹 애플리케이션 방화벽과 통합됩니다.
    • 라우팅 유연성: 애플리케이션 팀이 애플리케이션의 향후 변경 내용을 지원하도록 수신 요구를 구성할 수 있습니다.
    • 트래픽 가속: anycast를 사용하여 가장 가까운 Azure 현재 지점에 도달하고 웹앱에 대한 가장 빠른 경로를 찾습니다.
    • 사용자 지정 도메인: 유연한 도메인 유효성 검사를 통해 사용자 지정 도메인 이름을 지원합니다.
    • 상태 프로브: 애플리케이션에는 지능형 상태 프로브 모니터링이 필요합니다. Azure Front Door는 프로브의 응답을 사용하여 클라이언트 요청을 라우팅하는 데 가장 적합한 원본을 결정합니다.
    • 모니터링 지원: Front Door 및 보안 패턴 모두에 대한 올인원 대시보드가 포함된 기본 제공 보고서를 지원합니다. Azure Monitor와 통합되는 경고를 구성할 수 있습니다. 애플리케이션에서 각 요청 및 실패한 상태 프로브를 기록할 수 있습니다.
    • DDoS 보호: 기본 제공 계층 3-4 DDoS 보호가 있습니다.
    • 콘텐츠 배달 네트워크: 콘텐츠 배달 네트워크를 사용하도록 Relecloud를 배치합니다. 콘텐츠 배달 네트워크는 사이트 가속을 제공합니다.
  • 웹 애플리케이션 방화벽: Azure 웹 애플리케이션 방화벽을 사용하여 일반적인 웹 악용 및 취약성으로부터 중앙 집중식 보호를 제공합니다. Relecloud는 다음과 같은 이유로 Azure 웹 애플리케이션 방화벽을 사용했습니다.

    • 글로벌 보호: 성능을 저하시키지 않고 향상된 글로벌 웹앱 보호를 제공합니다.
    • 봇넷 보호: 팀은 봇넷과 관련된 보안 문제를 해결하기 위해 설정을 모니터링하고 구성할 수 있습니다.
    • 온-프레미스와의 패리티: 온-프레미스 솔루션이 IT에서 관리하는 웹 애플리케이션 방화벽 뒤에서 실행되었습니다.
    • 사용 편의성: 웹 애플리케이션 방화벽이 Azure Front Door와 통합됩니다.
  • 구성 스토리지: 웹앱에 앱 구성 스토리지를 추가할지 여부를 선택합니다. Azure 앱 구성은 애플리케이션 설정 및 기능 플래그를 중앙에서 관리하기 위한 서비스입니다. App Configuration 모범 사례를 검토하여 이 서비스가 앱에 적합한지 여부를 결정합니다. Relecloud는 파일 기반 구성을 애플리케이션 플랫폼 및 코드와 통합되는 중앙 구성 저장소로 바꾸고자 했습니다. 다음과 같은 이유로 아키텍처에 App Configuration을 추가했습니다.

    • 유연성: 기능 플래그를 지원합니다. 기능 플래그를 사용하면 사용자가 앱을 다시 배포하지 않고 프로덕션 환경에서 초기 미리 보기 기능을 옵트인 및 옵트아웃할 수 있습니다.
    • Git 파이프라인 지원: Git 리포지토리에 필요한 구성 데이터의 원본입니다. 중앙 구성 저장소의 데이터를 업데이트하는 데 필요한 파이프라인입니다.
    • 관리 ID 지원: 관리 ID를 지원하여 구성 저장소에 대한 연결을 간소화하고 보호합니다.
  • 비밀 관리자: Azure에서 관리할 비밀이 있는 경우 Azure Key Vault를 사용합니다. ConfigurationBuilder 개체를 사용하여 .NET 앱에 Key Vault를 통합할 수 있습니다. Relecloud의 온-프레미스 웹앱은 코드 구성 파일에 비밀을 저장하지만 RBAC 및 감사 컨트롤을 지원하는 위치에 비밀을 저장하는 것이 더 나은 보안 방법입니다. 관리 ID는 Azure 리소스에 연결하기 위한 기본 솔루션이지만 Relecloud에는 관리하는 데 필요한 애플리케이션 비밀이 있습니다. Relecloud는 다음과 같은 이유로 Key Vault를 사용했습니다.

    • 암호화: 미사용 및 전송 중인 암호화를 지원합니다.
    • 관리 ID 지원: 애플리케이션 서비스는 관리 ID를 사용하여 비밀 저장소에 액세스할 수 있습니다.
    • 모니터링 및 로깅: 저장된 비밀이 변경될 때 감사 액세스를 용이하게 하고 경고를 생성합니다.
    • 통합: Azure 구성 저장소(App Configuration) 및 웹 호스팅 플랫폼(App Service)과 네이티브 통합을 제공합니다.
  • 스토리지 솔루션: 요구 사항에 따라 적절한 스토리지 솔루션을 선택하려면 Azure Storage 옵션을 검토합니다. Relecloud의 온-프레미스 웹앱에는 각 웹 서버에 디스크 스토리지가 탑재되었지만 팀은 외부 데이터 스토리지 솔루션을 사용하고자 했습니다. Relecloud는 다음과 같은 이유로 Azure Blob Storage를 선택했습니다.

    • 보안 액세스: 웹앱은 익명 액세스를 사용하여 공용 인터넷에 노출된 스토리지에 액세스하기 위한 엔드포인트를 제거할 수 있습니다.
    • 암호화: 미사용 및 전송 중인 데이터를 암호화합니다.
    • 복원력: ZRS(영역 중복 스토리지)를 지원합니다. 영역 중복 스토리지는 주 지역의 세 Azure 가용성 영역에서 데이터를 동기적으로 복제합니다. 각 가용성 영역은 독립적인 전원, 냉각 및 네트워킹이 있는 별도의 물리적 위치에 있습니다. 이 구성은 티켓 이미지를 손실에 대해 복원력 있게 만들어야 합니다.
  • 엔드포인트 보안: Azure Private Link를 사용하여 가상 네트워크의 프라이빗 엔드포인트를 통해 서비스로서의 플랫폼 솔루션에 액세스합니다. 가상 네트워크와 서비스 간의 트래픽은 Microsoft 백본 네트워크를 통해 이동합니다. Relecloud는 다음과 같은 이유로 Private Link를 선택했습니다.

    • 향상된 보안 통신: 애플리케이션이 Azure 플랫폼의 서비스에 비공개로 액세스하고 데이터 누출을 방지할 수 있도록 데이터 저장소의 네트워크 공간을 줄일 수 있습니다.
    • 최소 작업: 프라이빗 엔드포인트는 웹앱에서 사용하는 웹앱 플랫폼 및 데이터베이스 플랫폼을 지원합니다. 두 플랫폼 모두 최소한의 변경을 위해 기존 온-프레미스 구성을 미러링합니다.
  • 네트워크 보안: Azure Firewall을 사용하여 네트워크 수준에서 인바운드 및 아웃바운드 트래픽을 제어합니다. Azure Bastion을 사용하여 RDP/SSH 포트를 노출하지 않고 가상 머신에 안전하게 연결합니다. Relecloud는 허브 및 스포크 네트워크 토폴로지와 공유 네트워크 보안 서비스를 허브에 배치하려고 했습니다. Azure Firewall은 스포크에서 모든 아웃바운드 트래픽을 검사하여 보안을 향상시켜 네트워크 보안을 강화합니다. Relecloud는 DevOps 서브넷의 점프 호스트에서 안전한 배포를 위해 Azure Bastion이 필요했습니다.

코드 지침

웹앱을 클라우드로 성공적으로 이동하려면 다시 시도 패턴, 회로 차단기 패턴 및 캐시 배제 디자인 패턴으로 웹앱 코드를 업데이트해야 합니다.

신뢰할 수 있는 필수 웹앱 아키텍처에서 디자인 패턴의 역할을 보여 주는 다이어그램

그림 3. 디자인 패턴의 역할입니다.

각 디자인 패턴은 잘 설계된 프레임워크의 더 많은 핵심 요소 중 하나에 부합하는 워크로드 디자인 이점을 제공합니다. 구현해야 하는 패턴의 개요는 다음과 같습니다.

  1. 다시 시도 패턴: 다시 시도 패턴은 간헐적으로 실패할 수 있는 작업을 다시 시도하여 일시적인 오류를 처리합니다. 다른 Azure 서비스에 대한 모든 아웃바운드 호출에서 이 패턴을 구현합니다.

  2. 회로 차단기 패턴: 회로 차단기 패턴은 애플리케이션이 일시적이지 않은 작업을 다시 시도하는 것을 방지합니다. 다른 Azure 서비스에 대한 모든 아웃바운드 호출에서 이 패턴을 구현합니다.

  3. 캐시 배제 패턴: 캐시 배제 패턴은 데이터 저장소보다 캐시에 더 자주 추가되고 캐시에서 검색됩니다. 데이터베이스에 대한 요청에 대해 이 패턴을 구현합니다.

디자인 패턴 안정성(RE) 보안(SE) CO(비용 최적화) 운영 우수성(OE) PE(성능 효율성) WAF 원칙 지원
패턴 다시 시도 RE:07
회로 차단기 패턴 RE:03
RE:07
PE:07
PE:11
캐시 배제 패턴 RE:05
PE:08
PE:12

재시도 패턴 구현

애플리케이션 코드에 재시도 패턴을 추가하여 임시 서비스 중단을 해결합니다. 이러한 중단을 일시적인 오류라고 합니다. 일시적인 오류는 일반적으로 몇 초 내에 자체적으로 해결됩니다. 다시 시도 패턴을 사용하면 실패한 요청을 다시 전송할 수 있습니다. 또한 실패를 허용하기 전에 요청 지연 및 시도 횟수를 구성할 수 있습니다.

  • 기본 제공 재시도 메커니즘 사용 대부분의 Azure 서비스에서 구현을 신속하게 처리해야 하는 기본 제공 재시도 메커니즘을 사용합니다. 예를 들어 참조 구현은 Entity Framework Core의 연결 복원력을 사용하여 요청의 재시도 패턴을 Azure SQL Database적용합니다(다음 코드 참조).

    services.AddDbContextPool<ConcertDataContext>(options => options.UseSqlServer(sqlDatabaseConnectionString,
        sqlServerOptionsAction: sqlOptions =>
        {
            sqlOptions.EnableRetryOnFailure(
            maxRetryCount: 5,
            maxRetryDelay: TimeSpan.FromSeconds(3),
            errorNumbersToAdd: null);
        }));
    
  • 다시 시도 프로그래밍 라이브러리를 사용합니다. HTTP 통신의 경우 Polly 또는 Microsoft.Extensions.Http.Resilience.와 같은 표준 복원력 라이브러리를 통합합니다. 이러한 라이브러리는 외부 웹 서비스와의 통신을 관리하는 데 중요한 포괄적인 재시도 메커니즘을 제공합니다. 예를 들어 참조 구현에서는 Polly를 사용하여 코드가 개체를 호출 IConcertSearchService 하는 개체를 생성할 때마다 재시도 패턴을 적용합니다(다음 코드 참조).

    private void AddConcertSearchService(IServiceCollection services)
    {
        var baseUri = Configuration["App:RelecloudApi:BaseUri"];
        if (string.IsNullOrWhiteSpace(baseUri))
        {
            services.AddScoped<IConcertSearchService, MockConcertSearchService>();
        }
        else
        {
            services.AddHttpClient<IConcertSearchService, RelecloudApiConcertSearchService>(httpClient =>
            {
                httpClient.BaseAddress = new Uri(baseUri);
                httpClient.DefaultRequestHeaders.Add(HeaderNames.Accept, "application/json");
                httpClient.DefaultRequestHeaders.Add(HeaderNames.UserAgent, "Relecloud.Web");
            })
            .AddPolicyHandler(GetRetryPolicy())
            .AddPolicyHandler(GetCircuitBreakerPolicy());
        }
    }
    
    private static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
    {
        var delay = Backoff.DecorrelatedJitterBackoffV2(TimeSpan.FromMilliseconds(500), retryCount: 3);
        return HttpPolicyExtensions
          .HandleTransientHttpError()
          .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
          .WaitAndRetryAsync(delay);
    }
    

회로 차단기 패턴 구현

회로 차단기 패턴을 사용하여 일시적인 오류가 아닌 서비스 중단을 처리합니다. 회로 차단기 패턴은 애플리케이션이 응답하지 않는 서비스에 계속 액세스하지 못하도록 합니다. 애플리케이션을 릴리스하고 CPU 주기를 낭비하지 않으므로 애플리케이션이 최종 사용자의 성능 무결성을 유지합니다.

예를 들어 참조 구현은 API에 대한 모든 요청에 회로 차단기 패턴을 적용합니다. 이 논리는 HandleTransientHttpError HTTP 요청을 검색하여 안전하게 다시 시도할 수 있지만 지정된 기간 동안 집계 오류 수를 제한합니다(다음 코드 참조).

private static IAsyncPolicy<HttpResponseMessage> GetCircuitBreakerPolicy()
{
    return HttpPolicyExtensions
        .HandleTransientHttpError()
        .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
        .CircuitBreakerAsync(5, TimeSpan.FromSeconds(30));
}

캐시 배제 패턴 구현

메모리 내 데이터 관리를 개선하기 위해 웹앱에 캐시 배제 패턴을 추가합니다. 이 패턴은 데이터 요청을 처리하고 캐시와 영구 스토리지(예: 데이터베이스) 간의 일관성을 보장하는 책임을 애플리케이션에 할당합니다. 응답 시간을 단축하고, 처리량을 향상시키며, 더 많은 크기 조정의 필요성을 줄입니다. 또한 기본 데이터 저장소의 부하를 줄여 안정성 및 비용 최적화를 개선합니다. Cache-Aside 패턴을 구현하려면 다음 권장 사항을 따릅니다.

  • 캐시를 사용하도록 애플리케이션을 구성합니다. 프로덕션 앱은 데이터베이스 쿼리를 줄여 성능을 향상시키고 부하 분산 장치가 트래픽을 균등하게 분산할 수 있도록 비스틱 세션을 사용하도록 설정하므로 Distributed Redis Cache를 사용해야 합니다. 예를 들어 참조 구현에서는 분산 Redis 캐시를 사용합니다. 이 메서드AddAzureCacheForRedis Azure Cache for Redis를 사용하도록 애플리케이션을 구성합니다(다음 코드 참조).

    private void AddAzureCacheForRedis(IServiceCollection services)
    {
        if (!string.IsNullOrWhiteSpace(Configuration["App:RedisCache:ConnectionString"]))
        {
            services.AddStackExchangeRedisCache(options =>
            {
                options.Configuration = Configuration["App:RedisCache:ConnectionString"];
            });
        }
        else
        {
            services.AddDistributedMemoryCache();
        }
    }
    
  • 필요한 데이터를 캐시합니다. 높은 필요 데이터에 Cache-Aside 패턴을 적용하여 효율성을 증폭합니다. Azure Monitor를 사용하여 데이터베이스의 CPU, 메모리 및 스토리지를 추적합니다. 이러한 메트릭은 캐시 배제 패턴을 적용한 후 더 작은 데이터베이스 SKU를 사용할 수 있는지 여부를 결정하는 데 도움이 됩니다. 예를 들어 참조 구현은 예정된 콘서트 페이지를 지원하는 필요한 데이터를 캐시합니다. 이 메서드는 GetUpcomingConcertsAsync SQL Database에서 Redis 캐시로 데이터를 끌어오고 최신 콘서트 데이터로 캐시를 채웁니다(다음 코드 참조).

    public async Task<ICollection<Concert>> GetUpcomingConcertsAsync(int count)
    {
        IList<Concert>? concerts;
        var concertsJson = await this.cache.GetStringAsync(CacheKeys.UpcomingConcerts);
        if (concertsJson != null)
        {
            // There is cached data. Deserialize the JSON data.
            concerts = JsonSerializer.Deserialize<IList<Concert>>(concertsJson);
        }
        else
        {
            // There's nothing in the cache. Retrieve data 
            // from the repository and cache it for one hour.
            concerts = await this.database.Concerts.AsNoTracking()
                .Where(c => c.StartTime > DateTimeOffset.UtcNow && c.IsVisible)
                .OrderBy(c => c.StartTime)
                .Take(count)
                .ToListAsync();
            concertsJson = JsonSerializer.Serialize(concerts);
            var cacheOptions = new DistributedCacheEntryOptions {
                AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1)
            };
            await this.cache.SetStringAsync(CacheKeys.UpcomingConcerts, concertsJson, cacheOptions);
        }
        return concerts ?? new List<Concert>();
    }
    
  • 캐시 데이터를 최신 상태로 유지합니다. 최신 데이터베이스 변경 내용과 동기화하도록 일반 캐시 업데이트를 예약합니다. 데이터 변동성 및 사용자 요구에 따라 최적의 새로 고침 속도를 결정합니다. 이렇게 하면 애플리케이션이 Cache-Aside 패턴을 사용하여 빠른 액세스 및 현재 정보를 모두 제공할 수 있습니다. 예를 들어 참조 구현은 1시간 동안만 데이터를 캐시하고 이 메서드를 사용하여 CreateConcertAsync 데이터가 변경되면 캐시 키를 지웁니다(다음 코드 참조).

    public async Task<CreateResult> CreateConcertAsync(Concert newConcert)
    {
        database.Add(newConcert);
        await this.database.SaveChangesAsync();
        this.cache.Remove(CacheKeys.UpcomingConcerts);
        return CreateResult.SuccessResult(newConcert.Id);
    }
    
  • 데이터 일관성을 보장합니다. 데이터베이스 쓰기 작업 직후 캐시를 업데이트하는 메커니즘을 구현합니다. 이벤트 기반 업데이트 또는 전용 데이터 관리 클래스를 사용하여 캐시 일관성을 보장합니다. 캐시를 데이터베이스 수정과 일관되게 동기화하는 것은 캐시 배제 패턴의 핵심입니다. 예를 들어 참조 구현은 메서드를 UpdateConcertAsync 사용하여 캐시의 데이터를 일관성 있게 유지합니다(다음 코드 참조).

    public async Task<UpdateResult> UpdateConcertAsync(Concert existingConcert), 
    {
       database.Update(existingConcert);
       await database.SaveChangesAsync();
       this.cache.Remove(CacheKeys.UpcomingConcerts);
       return UpdateResult.SuccessResult();
    }
    

구성 지침

다음 섹션에서는 구성 업데이트를 구현하는 방법에 대한 지침을 제공합니다. 각 섹션은 잘 설계된 프레임워크의 하나 이상의 기둥에 맞춥니다.

구성 안정성(RE) 보안(SE) CO(비용 최적화) 운영 우수성(OE) PE(성능 효율성) WAF 원칙 지원
사용자 인증 및 권한 부여 구성 SE:05
OE:10
관리 ID 구현 SE:05
OE:10
적절한 크기 환경 CO:05
CO:06
자동 크기 조정을 구현 RE:06
CO:12
PE:05
리소스 배포 자동화 OE:05
모니터링 구현 OE:07
PE:04

사용자 인증 및 권한 부여 구성

웹 애플리케이션을 Azure로 마이그레이션할 때 사용자 인증 및 권한 부여 메커니즘을 구성합니다. 다음 권장 사항을 따릅니다.

  • ID 플랫폼을 사용합니다. Microsoft ID 플랫폼을 사용하여 웹앱 인증설정합니다. 이 플랫폼은 단일 Microsoft Entra 디렉터리, 여러 조직의 여러 Microsoft Entra 디렉터리 및 Microsoft ID 또는 소셜 계정을 사용하는 애플리케이션을 지원합니다.

  • 앱 등록을 만듭니다. Microsoft Entra ID에는 기본 테넌트에서 애플리케이션 등록이 필요합니다. 애플리케이션 등록을 통해 웹앱에 액세스하는 사용자에게 기본 테넌트에 ID가 있는지 확인합니다.

  • 플랫폼 기능을 사용합니다. 플랫폼 기능을 사용하여 사용자를 인증하고 데이터에 액세스하여 사용자 지정 인증 코드의 필요성을 최소화합니다. 예를 들어 App Service 는 기본 제공 인증 지원을 제공하므로 웹앱에서 최소 또는 전혀 코드를 작성하지 않고 사용자를 로그인하고 데이터에 액세스할 수 있습니다.

  • 애플리케이션에서 권한 부여를 적용합니다. RBAC(역할 기반 액세스 제어)를 사용하여 애플리케이션 역할에 최소 권한을 할당합니다. 서로 다른 사용자 작업에 대한 특정 역할을 정의하여 겹치지 않도록 하고 명확성을 보장합니다. 사용자를 적절한 역할에 매핑하고 필요한 리소스 및 작업에만 액세스할 수 있는지 확인합니다.

  • 스토리지에 대한 임시 액세스를 선호합니다. 임시 사용 권한을 사용하여 SAS(공유 액세스 서명)와 같은 무단 액세스 및 위반으로부터 보호합니다. 임시 액세스 권한을 부여할 때 사용자 위임 SAS를 사용하여 보안을 최대화합니다. Microsoft Entra ID 자격 증명을 사용하고 영구 스토리지 계정 키가 필요하지 않은 유일한 SAS입니다.

  • Azure에서 권한 부여를 적용합니다. Azure RBAC를 사용하여 사용자 ID에 최소 권한을 할당합니다. Azure RBAC는 Azure 리소스 ID가 액세스할 수 있는 항목, 해당 리소스로 수행할 수 있는 작업 및 액세스 권한이 있는 영역을 결정합니다.

  • 영구 관리자 권한은 사용하지 않습니다. Microsoft Entra Privileged Identity Management를 사용하여 권한 있는 작업에 대한 Just-In-Time 액세스 권한을 부여합니다. 예를 들어 개발자는 데이터베이스를 만들거나 삭제하고, 테이블 스키마를 수정하고, 사용자 권한을 변경하려면 관리자 수준의 액세스 권한이 필요한 경우가 많습니다. Just-In-Time 액세스를 통해 사용자 ID는 권한 있는 작업을 수행할 수 있는 임시 권한을 받습니다.

관리 ID 구현

관리 ID를 지원하는 모든 Azure 서비스에 대해 관리 ID를 사용합니다. 관리 ID를 사용하면 Azure 리소스(워크로드 ID)가 자격 증명을 관리하지 않고도 다른 Azure 서비스에 인증하고 상호 작용할 수 있습니다. 하이브리드 및 레거시 시스템은 마이그레이션을 간소화하기 위해 온-프레미스 인증 솔루션을 유지할 수 있지만 가능한 한 빨리 관리 ID로 전환해야 합니다. 관리 ID를 구현하려면 다음 권장 사항을 따릅니다.

  • 올바른 유형의 관리 ID를 선택합니다. 동일한 권한 집합이 필요한 둘 이상의 Azure 리소스가 있는 경우 사용자 할당 관리 ID를 선호합니다. 이 설정은 각 리소스에 대해 시스템 할당 관리 ID를 만들고 모든 리소스에 동일한 권한을 할당하는 것보다 더 효율적입니다. 그렇지 않으면 시스템 할당 관리 ID를 사용합니다.

  • 최소 권한을 구성합니다. Azure RBAC를 사용하여 데이터베이스의 CRUD 작업 또는 비밀 액세스와 같은 작업에 중요한 권한만 부여합니다. 워크로드 ID 권한은 영구적이므로 워크로드 ID에 대한 Just-In-Time 또는 단기 권한을 제공할 수 없습니다. Azure RBAC가 특정 시나리오를 다루지 않는 경우 Azure RBAC를 Azure 서비스 수준 액세스 정책으로 보완합니다.

  • 남은 비밀을 보호합니다. Azure Key Vault나머지 비밀을 저장합니다. 각 HTTP 요청 중에 대신 애플리케이션 시작 시 Key Vault에서 비밀을 로드합니다. HTTP 요청 내의 고주파 액세스는 Key Vault 트랜잭션 제한을 초과 할 수 있습니다. 애플리케이션 구성을 Azure 앱 구성저장합니다.

예를 들어 참조 구현은 SQL 데이터베이스 연결 문자열 인수를 사용 Authentication 하므로 App Service는 관리 IDServer=tcp:my-sql-server.database.windows.net,1433;Initial Catalog=my-sql-database;Authentication=Active Directory Default를 사용하여 SQL 데이터베이스에 연결할 수 있습니다. 웹 API가 DefaultAzureCredential 관리 ID를 사용하여 Key Vault에 연결할 수 있도록 허용합니다(다음 코드 참조).

    builder.Configuration.AddAzureAppConfiguration(options =>
    {
         options
            .Connect(new Uri(builder.Configuration["Api:AppConfig:Uri"]), new DefaultAzureCredential())
            .ConfigureKeyVault(kv =>
            {
                // Some of the values coming from Azure App Configuration
                // are stored in Key Vault. Use the managed identity
                // of this host for the authentication.
                kv.SetCredential(new DefaultAzureCredential());
            });
    });

적절한 크기 환경

초과하지 않고 각 환경의 요구 사항을 충족하는 Azure 서비스의 SKU(성능 계층)를 사용합니다. 환경 크기를 조정하려면 다음 권장 사항을 따르세요.

  • 비용을 예측합니다. Azure 가격 계산기를 사용하여 각 환경의 비용을 예측합니다.

  • 비용 최적화 프로덕션 환경. 프로덕션 환경에는 SLA(서비스 수준 계약), 기능 및 프로덕션에 필요한 규모를 충족하는 SKU가 필요합니다. 리소스 사용량을 지속적으로 모니터링하고 실제 성능 요구 사항에 맞게 SKU를 조정합니다.

  • 비용 최적화 사전 프로덕션 환경. 사전 프로덕션 환경에서는 저렴한 리소스를 사용하고, 불필요한 서비스를 사용하지 않도록 설정하고, Azure 개발/테스트 가격 책정과 같은 할인을 적용해야 합니다. 사전 프로덕션 환경이 프로덕션 환경과 충분히 유사하여 위험이 발생하지 않도록 합니다. 이 잔액을 통해 불필요한 비용을 발생시키지 않고도 테스트가 효과적으로 유지됩니다.

  • IaC(Infrastructure as Code)를 사용하여 SKU를 정의합니다. IaC를 구현하여 환경에 따라 올바른 SKU를 동적으로 선택하고 배포합니다. 이 방법은 일관성을 향상시키고 관리를 간소화합니다.

예를 들어 참조 구현은 Bicep 매개 변수를 사용하여 프로덕션 환경에 더 비싼 SKU(계층)를 배포합니다.

    var redisCacheSkuName = isProd ? 'Standard' : 'Basic'
    var redisCacheFamilyName = isProd ? 'C' : 'C'
    var redisCacheCapacity = isProd ? 1 : 0

자동 크기 조정을 구현

자동 크기 조정을 사용하면 웹앱이 복원력 있고 응답성이 뛰어나며 동적 워크로드를 효율적으로 처리할 수 있습니다. 자동 크기 조정을 구현하려면 다음 권장 사항을 따릅니다.

  • 스케일 아웃을 자동화합니다. Azure 자동 크기 조정을 사용하여 프로덕션 환경에서 수평 크기 조정을 자동화합니다. 애플리케이션에서 다양한 부하를 처리할 수 있도록 주요 성능 메트릭에 따라 스케일 아웃하도록 자동 크기 조정 규칙을 구성합니다.

  • 크기 조정 트리거를 구체화합니다. 애플리케이션의 크기 조정 요구 사항에 익숙하지 않은 경우 초기 크기 조정 트리거로 CPU 사용률로 시작합니다. RAM, 네트워크 처리량 및 디스크 I/O와 같은 다른 메트릭을 포함하도록 크기 조정 트리거를 구체화합니다. 목표는 성능 향상을 위해 웹 애플리케이션의 동작과 일치하도록 하는 것입니다.

  • 스케일 아웃 버퍼를 제공합니다. 최대 용량에 도달하기 전에 트리거할 크기 조정 임계값을 설정합니다. 예를 들어 100%에 도달할 때까지 기다리지 않고 CPU 사용률이 85%로 조정되도록 구성합니다. 이 사전 예방적 접근 방식은 성능을 유지하고 잠재적인 병목 상태를 방지하는 데 도움이 됩니다.

리소스 배포 자동화

자동화를 사용하여 모든 환경에서 Azure 리소스 및 코드를 배포하고 업데이트합니다. 다음 권장 사항을 따릅니다.

  • 인프라를 코드로 사용합니다. CI/CD(지속적인 통합 및 지속적인 업데이트) 파이프라인을 통해 코드로 인프라를 배포합니다. Azure에는 모든 Azure 리소스에 대해 미리 작성된 Bicep, ARM(JSON) 및 Terraform 템플릿이 있습니다 .

  • CI/CD(연속 통합/지속적인 배포) 파이프라인을 사용합니다. CI/CD 파이프라인을 사용하여 소스 제어에서 테스트, 스테이징 및 프로덕션과 같은 다양한 환경으로 코드를 배포합니다. GitHub 프로젝트용 Azure DevOps 또는 GitHub Actions를 사용하는 경우 Azure Pipelines를 활용합니다.

  • 단위 테스트를 통합합니다. App Services에 배포하기 전에 파이프라인 내의 모든 단위 테스트 실행 및 전달 우선 순위를 지정합니다. SonarQube와 같은 코드 품질 및 검사 도구를 통합하여 포괄적인 테스트 범위를 달성합니다.

  • 모의 프레임워크를 채택합니다. 외부 엔드포인트를 포함하는 테스트의 경우 모의 프레임워크를 활용합니다. 이러한 프레임워크를 사용하면 시뮬레이션된 엔드포인트를 만들 수 있습니다. 실제 외부 엔드포인트를 구성하고 환경 전체에서 균일한 테스트 조건을 보장할 필요가 없습니다.

  • 보안 검사를 수행합니다. SAST(정적 애플리케이션 보안 테스트)를 사용하여 소스 코드에서 보안 결함 및 코딩 오류를 찾습니다. 또한 SCA(소프트웨어 컴퍼지션 분석)를 수행하여 타사 라이브러리 및 구성 요소에서 보안 위험을 검사합니다. 이러한 분석을 위한 도구는 GitHub와 Azure DevOps 모두에 쉽게 통합됩니다.

모니터링 구현

애플리케이션 및 플랫폼 모니터링을 구현하여 웹앱의 운영 우수성과 성능 효율성을 향상시킵니다. 모니터링을 구현하려면 다음 권장 사항을 따릅니다.

  • 애플리케이션 원격 분석을 수집합니다. Azure 애플리케이션 Insights에서 자동 침입을 사용하여 코드 변경 없이 요청 처리량, 평균 요청 기간, 오류 및 종속성 모니터링과 같은 애플리케이션 원격 분석을 수집합니다.

    참조 구현은 NuGet 패키지 Microsoft.ApplicationInsights.AspNetCore 에서 원격 분석 컬렉션을 사용하도록 설정하는 데 사용합니다AddApplicationInsightsTelemetry(다음 코드 참조).

    public void ConfigureServices(IServiceCollection services)
    {
       ...
       services.AddApplicationInsightsTelemetry(Configuration["App:Api:ApplicationInsights:ConnectionString"]);
       ...
    }
    
  • 사용자 지정 애플리케이션 메트릭을 만듭니다. 사용자 지정 애플리케이션 원격 분석에 코드 기반 계측을 사용합니다. 코드에 Application Insights SDK를 추가하고 Application Insights API를 사용합니다.

    참조 구현은 카트 활동과 관련된 이벤트에 대한 원격 분석을 수집합니다. this.telemetryClient.TrackEvent 은 카트에 추가된 티켓을 계산합니다. 이벤트 이름(AddToCart)을 제공하고 및 (다음 코드 참조)가 있는 concertId count사전을 지정합니다.

    this.telemetryClient.TrackEvent("AddToCart", new Dictionary<string, string> {
        { "ConcertId", concertId.ToString() },
        { "Count", count.ToString() }
    });
    
  • 플랫폼을 모니터링합니다. 지원되는 모든 서비스에 대한 진단을 사용하도록 설정하고 상관 관계를 위해 애플리케이션 로그와 동일한 대상으로 진단을 보냅니다. Azure 서비스는 플랫폼 로그를 자동으로 만들지만 진단을 사용하도록 설정할 때만 저장합니다. 진단을 지원하는 각 서비스에 대한 진단 설정을 사용하도록 설정합니다.

참조 구현 배포

참조 구현은 개발자가 온-프레미스 ASP.NET 애플리케이션에서 Azure로의 시뮬레이트된 마이그레이션을 안내하며 초기 채택 단계에서 필요한 변경 사항을 강조 표시합니다. 이 예제에서는 온-프레미스 웹 애플리케이션을 통해 티켓을 판매하는 가상의 회사 Relecloud에 대한 콘서트 티켓 애플리케이션을 사용합니다. Relecloud는 웹 애플리케이션에 대해 다음 목표를 설정합니다.

  • 저렴한 고가용성 코드 변경 구현
  • 99.9%의 SLO(서비스 수준 목표) 달성
  • DevOps 사례 채택
  • 비용 최적화 환경 만들기
  • 안정성 및 보안 향상

Relecloud는 온-프레미스 인프라가 이러한 목표를 달성하기 위한 비용 효율적인 솔루션이 아니라고 판단했습니다. 그들은 CAMS 웹 애플리케이션을 Azure로 마이그레이션하는 것이 즉각적이고 미래의 목표를 달성하는 가장 비용 효율적인 방법이라고 결정했습니다. 다음 아키텍처는 Relecloud의 신뢰할 수 있는 웹앱 패턴 구현의 끝 상태를 나타냅니다.

참조 구현의 아키텍처를 보여 주는 다이어그램그림 3. 참조 구현의 아키텍처입니다. 이 아키텍처의 Visio 파일을 다운로드합니다.