[C#] Polly Nuget 패키지 - Circuit Breaker

참조


Polly 란?

  • Polly 패키지는 재시도, 시간 초과 등에 유연하고 스레드로부터 안전한 방식으로 표현할 수 있게 해주는 .NET 복원력 및 일시적인 오류를 처리해주는 라이브러리입니다.

Circuit Breaker 란?

  • 원래의 서킷 브레이커란, 회로 차단기에서 유래한 용어입니다.
  • 원래는 전기 회로에 과부하, 누전이 생기지 않도록 자동으로 회로를 정지 시켰다가 복귀 시키는 장치입니다.

Polly Circuit Breaker 원리

  • Circuit Breaker닫힌 상태(Close) 에서 시작하는 상태 기계로 볼 수 있습니다.
  • 이것은 정상 상태이며 이를 통해 요청의 흐름을 허용합니다.
  • 문제가 감지되면 차단기가 열린 상태로 이동하여 지정된 기간 동안 모든 요청을 차단합니다.
  • 해당 기간이 경과한 후 회로 차단기는 첫 번째 요청이 테스트 요청으로 처리되는 Half-Open 상태로 이동합니다.
  • 이 요청이 성공하면 회로가 닫히고 정상 작동이 재개되지만 실패하면 회로는 다시 열린 상태로 돌아가고 지정된 기간동안 그대로 유지되어 Half-Open 상태로 이동합니다.
  • Circuit Breaker 는 다음 상태 사이를 이동할 수 있습니다.

  • Polly 는 정책의 두 가지 변형을 제공합니다.
  • 지정된 수의 연속 오류가 발생할 경우 연결을 차단하는 기본 회로 차단기와 지정된 기간 동안 지정된 비율의 오류가 발생하고 최소 횟수가 초과되면 연결을 차단하는 고급 회로 차단기입니다.

시나리오

  • C# 으로 gRPC Server/Client 서비스를 생성하고 간단하게 로직을 구현합니다.

  • 여기서, Client 에서 Server 의 접속 정보를 다르게 하여 RpcException 이 발생하도록 합니다.

  • 실제 RpcException 에러가 발생 하였을 때, Polly 가 RpcException 에러를 감지하고 실제로 Circuit Breaker 를 진행하는지 테스트 진행합니다.


Polly NuGet Package 설치

  • 먼저, C# Project 에 Polly NuGet Package 설치 진행합니다.

PMC 명령어 설치

  • NuGet Package Manager Command 로 설치할 경우, 다음 명령어로 설치 진행 가능합니다.
Install-Package Polly

NuGet Package 설치

  • Polly 검색후, 다음 아이콘으로 생긴 NuGet 을 설치 진행합니다.

    참고로, Polly 는 gRPC 프로젝트에서 Client 프로젝트에 설치 하였습니다. 저는 Client 에서 Server 의 접속이 끊어졌을 경우 테스트 하였기 때문에 Polly 패키지를 Client에 추가하였습니다.


Server 프로젝트 생성

  • gRPC Server 프로젝트는 ASP.NET Core gRPC 서비스 프로젝트로 생성하였습니다.
  • ASP.NET Core gRPC 서비스 프로젝트를 생성하게 되면, 기본으로 Protos 파일이 생성이 되고, 해당 디렉토리 안에 greet.proto 파일이 생성됩니다.
  • 또한, GreeterService.cs 클래스가 자동으로 생성되며, 해당 클래스 안에는 gRPC 서버 로직이 구현되어 있습니다.
  • 해당 프로젝트 생성 과정은 생략 하도록 하겠습니다.

Client 프로젝트 생성

  • Client 프로젝트는 콘솔 프로젝트 로 생성하였습니다.
  • 그리고 다음 3가지의 NuGet Package 를 설치 하였습니다.
    • Google.Protobuf
    • Grpc.Net.Client
    • Grpc.Tools
  • 위 3개의 NuGet Package를 설치 진행 되어야 gRPC 통신을 진행할 수 있습니다.

Client 프로그램에 Polly Circuit Breaker 내용 추가

  • 이제 Client 프로그램에 Circuit Breaker 내용을 다음과 같이 추가하였습니다.
  • 아래 코드는 RpcException 이 발생할 경우, 처음에는 3번까지는 Retry 시도를 진행합니다.
  • 그리고 3번의 횟수 초과시 BrokenCircuitException 이 발생하고, 15초 대기하여 다시 연결을 진행하도록 하는 로직입니다.
using Grpc.Core;
using Grpc.Net.Client;
using gRPCService;
using Polly;
using Polly.CircuitBreaker;

var policy = Policy.Handle<RpcException>(r => r.StatusCode != StatusCode.OK)
    .CircuitBreakerAsync(exceptionsAllowedBeforeBreaking: 3, durationOfBreak: TimeSpan.FromSeconds(10));

while (true)
{
    try
    {
        Console.WriteLine($"CircuitState : {policy.CircuitState}");

        var result = await policy.ExecuteAsync(async () => await DoSomething());

        return;
    }
    catch (BrokenCircuitException)
    {
        Console.WriteLine("The circuit breaker tripped and is temporarily disallowing requests. Will wait before trying again");
        await Task.Delay(TimeSpan.FromSeconds(15));
    }
    catch (RpcException)
    {
        Console.WriteLine("RpcException exception while sending request. Will try again.");
    }
}

/// <summary>
/// gRPC Server 에게 메시지 보내기
/// </summary>
static async Task<string> DoSomething()
{
    var channel = GrpcChannel.ForAddress("https://localhost:7243");
    var greeterClient = new Greeter.GreeterClient(channel);

    var greeterRequest = new HelloRequest { Name = "Beom" };

    var greeter = await greeterClient.SayHelloAsync(greeterRequest);

    Console.WriteLine($"{greeter.Message}");

    Console.WriteLine($"Successfully send request");

    return greeter.Message;
}

실행 결과

  • 실제 프로그램을 실행하여 Circuit Breaker 가 정상적으로 실행되는지 테스트 진행하였습니다.
  • 우선 처음 3회는 Circuit State = Closed 상태여야 합니다.
  • 그리고 3회 시도 후, 이제는 Circuit State = Open 상태로 바뀐 후, BrokenCircuitException 이 발생하여 15초 대기합니다.
  • 그리고 Circuit State = Half Open 로 변경 후 다시 gRPC 서버에게 접속 요청을 진행합니다.
  • 하지만, 여전히 Server와의 접속이 되지 않기 때문에 Circuit State = Open 으로 상태가 변경되고 또 BrokenCircuitException 예외가 발생하여 15초 대기 하는 그런 패턴이 계속 반복되는 것을 확인할 수 있습니다.
CircuitState : Closed
RpcException exception while sending request. Will try again.
CircuitState : Closed
RpcException exception while sending request. Will try again.
CircuitState : Closed
RpcException exception while sending request. Will try again.
CircuitState : Open
The circuit breaker tripped and is temporarily disallowing requests. Will wait before trying again
CircuitState : HalfOpen
RpcException exception while sending request. Will try again.
CircuitState : Open
The circuit breaker tripped and is temporarily disallowing requests. Will wait before trying again
CircuitState : HalfOpen
RpcException exception while sending request. Will try again.
CircuitState : Open
The circuit breaker tripped and is temporarily disallowing requests. Will wait before trying again
CircuitState : HalfOpen
RpcException exception while sending request. Will try again.
CircuitState : Open
The circuit breaker tripped and is temporarily disallowing requests. Will wait before trying again
CircuitState : HalfOpen
....
728x90

이 글을 공유하기

댓글

Designed by JB FACTORY