Polly와 함께 탄력적인 .NET 애플리케이션 구축

발행: (2025년 12월 27일 오후 01:31 GMT+9)
10 min read
원문: Dev.to

Source: Dev.to

현대 애플리케이션은 거의 독립적으로 존재하지 않습니다. 데이터베이스, 서드파티 API, 마이크로서비스, 그리고 클라우드 리소스와 지속적으로 통신합니다.

이 때문에 실패는 예외가 아니라 기대치입니다.

일시적인 네트워크 문제, 일시적인 서비스 중단, 혹은 짧은 타임아웃은 복원력을 고려하지 않을 경우 잘 설계된 시스템조차 쉽게 무너뜨릴 수 있습니다.

이 글에서는 다음을 살펴볼 것입니다:

  • 소프트웨어 시스템에서 복원력(resilience) 이 의미하는 바
  • 일반적인 복원력 패턴들
  • Polly를 사용하여 .NET에서 RetryCircuit Breaker 패턴을 구현하는 방법

소프트웨어 시스템에서 회복탄력성이란?

회복탄력성은 애플리케이션이 다음을 할 수 있는 능력입니다:

  • 실패를 우아하게 처리한다
  • 일시적인 문제에서 자동으로 복구한다
  • 가용성과 응답성을 유지한다

무언가 잘못되어도 시스템이 충돌하거나 사용자를 차단하지 않고, 회복탄력적인 시스템은 적응하여 계속 작동합니다. 회복탄력성 메커니즘을 안전망이라고 생각하세요 — 이는 애플리케이션이 불가피하게 실패할 때 잡아줍니다.

일시적 실패 이해

**일시적 실패(transient failure)**는 짧은 시간 후에 스스로 해결되는 일시적인 문제를 말합니다. 흔한 예시로는 다음과 같습니다:

  • 일시적인 네트워크 오류
  • API 타임아웃
  • 단기간에 발생하는 데이터베이스 연결 실패
  • 클라우드 서비스 제한(스로틀링)

이러한 실패는 영구적인 오류로 간주해서는 안 됩니다. 짧은 지연 후에 작업을 다시 시도하면 성공할 가능성이 높습니다.

재시도 패턴 (Retry Pattern)

재시도 패턴이란?

Retry Pattern은 실패한 작업을 제한된 횟수만큼 자동으로 다시 실행하고, 그 이후에 포기합니다.

언제 재시도를 사용해야 할까요?

  • 네트워크 호출
  • 외부 API
  • 메시지 큐
  • 클라우드 리소스

언제 재시도를 사용하면 안 될까요?

  • 검증 오류
  • 인증 실패
  • 비즈니스 규칙 위반

Polly를 이용한 재시도 예제

var retryPolicy = Policy
    .Handle<HttpRequestException>()
    .WaitAndRetryAsync(
        retryCount: 3,
        sleepDurationProvider: attempt => TimeSpan.FromSeconds(2),
        onRetry: (exception, timeSpan, retryCount, context) =>
        {
            Console.WriteLine($"Retry {retryCount} after {timeSpan.TotalSeconds}s");
        });

이 코드가 하는 일

  • 요청을 최대 3번 재시도합니다
  • 재시도 사이에 2초 대기합니다
  • HttpRequestException이 발생했을 때만 재시도합니다

이 접근 방식은 일시적인 오류에 대한 성공률을 크게 높이며 사용자 경험에 미치는 영향을 최소화합니다.

Source:

회로 차단기 패턴

회로 차단기가 해결하는 문제

제3자 서비스를 호출했는데 완전히 다운된 경우를 상상해 보세요:

  • 요청이 계속 실패한다
  • 스레드가 차단된 상태로 남는다
  • 시스템 자원이 고갈된다
  • 실패가 시스템 전체로 전파된다

이것이 작은 실패가 시스템 전체 장애로 이어지는 방식입니다.

회로 차단기란?

회로 차단기는 애플리케이션이 실패할 가능성이 높은 작업을 실행하지 않도록 방지합니다. 전기 회로 차단기와 유사하게 동작합니다:

  • 반복적인 실패를 감지한다
  • 일시적으로 요청 전송을 중단한다
  • 시스템이 회복될 수 있도록 한다

회로 차단기 상태

상태설명
Closed요청이 정상적으로 흐른다.
Open요청이 즉시 거부된다 (fail‑fast).
Half‑Open복구 여부를 확인하기 위해 제한된 수의 테스트 요청을 허용한다.

Polly를 이용한 회로 차단기 예제

var circuitBreakerPolicy = Policy
    .Handle<HttpRequestException>()
    .CircuitBreakerAsync(
        exceptionsAllowedBeforeBreaking: 5,
        durationOfBreak: TimeSpan.FromSeconds(30),
        onBreak: (exception, duration) =>
        {
            Console.WriteLine("Circuit opened");
        },
        onReset: () =>
        {
            Console.WriteLine("Circuit closed");
        },
        onHalfOpen: () =>
        {
            Console.WriteLine("Circuit half-open");
        });

이 코드가 하는 일

  • 연속 5번 실패가 발생하면 회로를 연다
  • 30초 동안 요청을 차단한다
  • 차단 기간이 끝난 뒤 자동으로 복구를 시도한다

재시도와 회로 차단기 결합

재시도만 사용하면 실패하는 서비스를 과부하 시킬 수 있습니다.
회로 차단기만 사용하면 과도하게 공격적일 수 있습니다.

실제 힘은 이들을 결합할 때 나옵니다.

var resiliencePolicy = Policy.WrapAsync(
    retryPolicy,
    circuitBreakerPolicy);

실행 예시

await resiliencePolicy.ExecuteAsync(async () =>
{
    var response = await httpClient.GetAsync("https://external-api.com/data");
    response.EnsureSuccessStatusCode();
});

이 설정은 다음을 보장합니다:

  • 일시적인 실패는 재시도됩니다
  • 지속적인 실패는 회로 차단을 트리거합니다
  • 시스템 안정성이 유지됩니다

왜 Polly인가?

Polly는 .NET 생태계에서 사실상의 복원력 라이브러리입니다. 이유는:

  • 유창하고 표현력 있는 API
  • 비동기 및 동기 작업 지원
  • HttpClientFactory와 쉽게 통합
  • 프로덕션 시스템에서 널리 사용

지원되는 패턴에는 다음이 포함됩니다:

  • 재시도
  • 회로 차단기
  • 타임아웃
  • 폴백
  • 벌크헤드 격리

실제 사용 사례

Polly는 특히 다음에 유용합니다:

  • 마이크로서비스 통신
  • 금융 및 트레이딩 시스템
  • 클라우드‑네이티브 애플리케이션
  • API 게이트웨이
  • SignalR 및 실시간 시스템

Any place where I/O 또는 원격 호출이 존재하는 모든 곳에서 복원력은 일급 고려사항이어야 합니다.

핵심 요점

  • 분산 시스템에서는 실패가 불가피합니다
  • 회복력은 작은 문제가 중단으로 이어지는 것을 방지합니다
  • 재시도는 일시적인 오류를 처리합니다
  • 회로 차단기는 시스템 안정성을 보호합니다
  • Polly는 .NET에서 회복력을 실용적이고 프로덕션 준비된 형태로 만들어 줍니다

최종 생각

복원력은 선택적인 기능이 아니라 현대 애플리케이션을 위한 설계 요구사항입니다. Polly와 같은 견고한 라이브러리를 사용해 Retry 및 Circuit Breaker와 같은 패턴을 구현하면 프로세스 외부의 환경이 비정상적일 때도 시스템을 가용하고, 반응성이 뛰어나며, 유지보수가 용이하도록 구축할 수 있습니다.

결론

검증된 패턴과 Polly 같은 라이브러리를 활용하면 다음과 같은 시스템을 구축할 수 있습니다:

  • 안정적
  • 확장 가능
  • 내결함성
  • 사용자 친화적

애플리케이션이 외부와 통신한다면, 탄력적이어야 합니다.

저는 Morteza Jangjoo이며 “누군가 나에게 설명해 주었으면 하는 것들을 설명합니다.”

Back to Blog

관련 글

더 보기 »