티스토리 뷰

728x90

서킷 브레이커 (Circuit Breaker)

서킷 브레이커?

서킷 브레이커는 분산 시스템에서 장애 전파를 방지하고 시스템의 안정성을 높이기 위한 디자인 패턴입니다. 전기 회로의 차단기에서 영감을 받아 만들어졌으며, 소프트웨어 시스템에서 비슷한 역할을 수행합니다.

작동 원리

  1. 서비스 호출을 지속적으로 모니터링합니다.
  2. 실패율이 설정된 임계값을 초과하면 '열린' 상태가 되어 호출을 차단합니다.
  3. 일정 시간 후 '반열린' 상태로 전환하여 제한적인 호출을 허용합니다.
  4. 호출이 성공하면 '닫힌' 상태(정상)로 돌아갑니다.

주요 상태

  1. 닫힘(Closed): 정상 상태. 모든 요청이 서비스로 전달됩니다.
  2. 열림(Open): 장애 상태. 모든 요청이 즉시 실패로 처리되거나 대체 응답을 반환합니다.
  3. 반열림(Half-Open): 복구 시도 상태. 제한된 수의 요청만 서비스로 전달하여 정상 여부를 확인합니다.

이점

  • 빠른 실패(Fast Fail): 장애 상황에서 불필요한 대기 시간을 줄입니다.
  • 점진적 복구: 시스템이 천천히 정상 상태로 돌아갈 수 있게 합니다.
  • 시스템 부하 감소: 과부하 상태의 서비스로의 요청을 제한합니다.
  • 장애 전파 방지: 한 서비스의 장애가 전체 시스템으로 확산되는 것을 막습니다.

구현 예시: Spring Cloud Circuit Breaker

Spring Cloud Circuit Breaker를 사용한 간단한 구현 예시입니다:

@RestController
public class CircuitBreakerController {

    private final ExampleService exampleService;

    public CircuitBreakerController(ExampleService exampleService) {
        this.exampleService = exampleService;
    }

    @GetMapping("/unreliable")
    @CircuitBreaker(name = "exampleBreaker", fallbackMethod = "fallback")
    public String unreliable() {
        return exampleService.unreliableMethod();
    }

    public String fallback(Throwable throwable) {
        return "Fallback response due to: " + throwable.getMessage();
    }
}

설정 예시 (application.yml):

resilience4j.circuitbreaker:
  instances:
    exampleBreaker:
      slidingWindowSize: 10
      failureRateThreshold: 50
      waitDurationInOpenState: 5s
      permittedNumberOfCallsInHalfOpenState: 3

설정 값 설명

  1. slidingWindowSize: 10
    • 의미: 서킷 브레이커가 상태를 결정하기 위해 고려하는 최근 호출의 수입니다.
    • 설명: 마지막 10번의 요청을 기준으로 실패율을 계산합니다.
  2. failureRateThreshold: 50
    • 의미: 서킷을 열기 위한 실패율 임계값(백분율)입니다.
    • 설명: 실패율이 50%를 초과하면 서킷이 열립니다.
  3. waitDurationInOpenState: 5s
    • 의미: 서킷이 열린 상태에서 반열림 상태로 전환되기까지 대기하는 시간입니다.
    • 설명: 서킷이 열린 후 5초 동안 모든 요청을 차단하고, 그 후 반열림 상태로 전환됩니다.
  4. permittedNumberOfCallsInHalfOpenState: 3
    • 의미: 반열림 상태에서 허용되는 호출 수입니다.
    • 설명: 반열림 상태에서 3개의 요청만 실제 서비스로 전달되어 서비스의 회복 여부를 판단합니다.

동작 시나리오

  1. 초기 상태 (서킷 닫힘):
    • 10번의 요청 중 6번 성공, 4번 실패 (실패율 40%)
    • 서킷 브레이커 닫힌 상태 유지
  2. 실패율 증가 (서킷 열림):
    • 다음 10번의 요청 중 7번 실패 (실패율 70%)
    • 실패율이 50% 초과로 서킷 브레이커 열림
    • 이후 모든 요청은 fallback 처리
  3. 대기 시간 (서킷 열림 유지):
    • 5초 동안 모든 요청 즉시 fallback 처리
  4. 반열림 상태:
    • 5초 후 '반열림' 상태로 전환
    • 3개의 요청만 실제 서비스로 전달
    • 성공 시 서킷 닫힘, 실패 시 다시 열림
  5. 정상화 (서킷 닫힘):
    • 3개의 요청 모두 성공 시 서킷 다시 닫힘
    • 정상적인 서비스 호출 재개
stateDiagram-v2
    [*] --> Closed: 초기 상태

    state Closed {
        RequestHandling: 요청 처리
        FailureRateCalc: 실패율 계산
        RequestHandling --> FailureRateCalc: 요청 완료
        FailureRateCalc --> RequestHandling: 실패율 < 임계값
    }

    state Open {
        BlockAll: 모든 요청 차단
        WaitCount: 대기 시간 카운트
        BlockAll --> WaitCount: 요청 발생
        WaitCount --> BlockAll: 대기 시간 < 설정값
    }

    state HalfOpen {
        LimitedRequests: 제한된 요청 허용
        SuccessRateCalc: 성공률 계산
        LimitedRequests --> SuccessRateCalc: 허용된 요청 완료
    }

    Closed --> Open: 실패율 > 임계값
    Open --> HalfOpen: 대기 시간 경과
    HalfOpen --> Closed: 성공률 > 임계값
    HalfOpen --> Open: 실패 발생

    note right of Closed : 정상 작동 상태
    note right of Open : 장애 상태
    note right of HalfOpen : 복구 시도 상태

주의사항 및 모범 사례

  1. 임계값 설정: 시스템 특성에 맞는 적절한 실패율 임계값 설정이 중요합니다.
  2. 타임아웃 설정: 서비스 호출 시 적절한 타임아웃을 설정하여 불필요한 대기를 방지합니다.
  3. fallback 전략: 서킷이 열렸을 때의 대체 응답을 신중히 설계합니다.
  4. 모니터링: 서킷 브레이커의 상태와 성능 지표를 지속적으로 모니터링합니다.
  5. 테스트: 다양한 장애 시나리오에 대한 철저한 테스트가 필요합니다.
  6. 점진적 적용: 중요도가 낮은 서비스부터 시작하여 점진적으로 적용합니다.

서킷 브레이커 패턴을 효과적으로 구현하면 시스템의 안정성과 복원력을 크게 향상시킬 수 있습니다. 하지만 각 시스템의 특성과 요구사항에 맞게 세심하게 설정하고 관리해야 합니다.

728x90
댓글