서킷 브레이커 패턴

HodaeSsi·2025년 1월 5일
0

서킷 브레이커(Circuit Breaker) 디자인 패턴

마이크로서비스(MSA)나 분산 환경에서 장애 전파를 막고, 빠른 예외 처리(fail-fast)를 제공하기 위해 널리 사용되는 서킷 브레이커(Circuit Breaker) 디자인 패턴을 정리해 보았습니다.


1. 서킷 브레이커(Circuit Breaker)란?

서킷 브레이커는 전기 회로 차단기(Circuit Breaker)의 개념을 서비스 간 통신에 적용한 디자인 패턴입니다.
어떤 외부 API나 서비스가 장애(오류가 연속 발생하거나 응답 시간이 지나치게 긴 경우 등)를 일으키면, 계속해서 재시도하기보다는 일정 조건이 충족될 때까지 해당 호출을 빠르게 차단합니다.

이를 통해,

  • 장애가 다른 서비스로 전파되는 것을 막고,
  • 시스템 자원을 낭비하지 않으며,
  • 사용자에게는 빠른 실패 응답을 하여 폴백(fallback) 로직을 실행하거나 대체 경로를 제공할 수 있습니다.

이 패턴은 특히 마이크로서비스 아키텍처분산 환경에서 자주 사용되는 패턴입니다.


2. 서킷 브레이커의 동작 원리

(1) Closed(닫힘) 상태

  • 기본 상태이며, 정상적으로 외부 서비스를 호출합니다.
  • 에러율(오류율)이 특정 임계치(threshold)를 넘어서면 Open(열림) 상태로 전환됩니다.

(2) Open(열림) 상태

  • 장애가 임계치를 넘어서면, 더 이상 외부 서비스로 요청을 보내지 않습니다.
  • 일정 시간 동안 이 상태를 유지하면서 바로 실패(Fail-fast) 처리를 합니다.
    → 즉시 예외를 반환하여 불필요한 대기나 재시도를 막습니다.
  • Open 상태 동안은 폴백 로직 등을 통해 사용자가 최소한의 응답이나 대체 서비스를 이용할 수 있도록 합니다.

(3) Half-Open(반 열림) 상태

  • Open 상태로부터 일정 시간이 지난 후, 재시도를 위해 반 열림 상태로 전환합니다.
  • 반 열림 상태에서는 일부 요청(테스트용 요청)만 외부 서비스로 보내봅니다.
    • 만약 이 요청이 성공하면 → 다시 Closed 상태로 전환하여 정상 흐름으로 복귀합니다.
    • 실패하면 → 다시 Open 상태로 전환되어 차단을 계속 유지합니다.

3. 서킷 브레이커를 구성할 때 고려해야 할 요소

  1. 오류(또는 타임아웃) 임계치 기준

    • “오류율이 50% 이상 연속으로 5번 발생하면 Open으로 전환”처럼 설정합니다.
    • 너무 빠르게 차단이 일어나면 정상적인 요청까지 막힐 수 있고, 너무 느리면 장애 전파를 막지 못합니다.
  2. Open 상태 유지 시간(Wait Duration in Open State)

    • 얼마 동안 Open 상태로 유지할지 결정해야 합니다.
    • 이 시간 동안에는 대부분 요청을 차단(fail-fast)합니다.
  3. Half-Open 상태에서의 재시도 횟수 (Permitted Number of Calls in Half-Open State)

    • 얼마나 많은 요청을 테스트 차원에서 허용할지, 해당 시도에서 성공/실패 기준을 어떻게 볼지 등 세부적인 설정을 잡아야 합니다.
  4. 폴백(Fallback) 로직

    • 외부 서비스가 장애 상태일 때 사용자에게 어떤 응답을 제공할지 (단순히 “오류”만 내려줄 것인지, 캐시나 다른 대체 경로를 통해 한정된 정보를 제공할 것인지)를 미리 마련해야 합니다.
  5. 모니터링 및 알림

    • 서킷 브레이커가 Open, Half-Open 상태로 자주 전환되는지 모니터링해야 합니다.
    • 장애의 징후를 빠르게 파악할 수 있도록 대시보드를 구축하거나 알림(Notification) 시스템과 연동하는 것도 중요합니다.

4. 구현 예시: Spring Boot + Resilience4j

자바/스프링 부트 환경에서 서킷 브레이커 패턴을 구현할 때 대표적으로 사용하는 라이브러리가 Resilience4j입니다.
CircuitBreaker 모듈 외에도 Bulkhead, RateLimiter, Retry 등 다양한 내결함성(Resilience) 패턴을 지원합니다.

(1) 라이브러리 추가

dependencies {
    implementation 'io.github.resilience4j:resilience4j-spring-boot2:1.7.0'
    // 버전은 상황에 맞게 최신으로 조정
}

(2) 설정(application.yml)

resilience4j:
  circuitbreaker:
    configs:
      default:
        registerHealthIndicator: true
        slidingWindowSize: 10               # 오류율 계산에 사용되는 호출 수
        permittedNumberOfCallsInHalfOpenState: 3
        minimumNumberOfCalls: 5             # 오류율 계산에 필요한 최소 호출 수
        failureRateThreshold: 50            # 오류율이 50% 이상이면 Open 상태로 전환
        waitDurationInOpenState: 10s        # Open 상태 유지 시간
        automaticTransitionFromOpenToHalfOpenEnabled: true
        # 그 외 timeoutDuration, slowCallRateThreshold 등 다양한 설정 가능
    instances:
      myServiceCircuitBreaker:
        baseConfig: default                 # 공통 설정 재사용
        # 인스턴스별로 다르게 지정할 수도 있음

(3) 적용 코드

import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;

@Service
public class MyService {

    // name에는 위에서 설정한 'myServiceCircuitBreaker' 또는 'default' 등 사용
    @CircuitBreaker(name = "myServiceCircuitBreaker", fallbackMethod = "fallbackForCallExternalService")
    public String callExternalService() {
        // 외부 API 호출 로직
        // 예: REST API 클라이언트 사용, FeignClient, WebClient 등
        // 여기서 장애가 연속 발생하면 서킷 브레이커가 개입
        return "성공 응답";
    }

    // fallbackMethod 시그니처는 원 메서드와 동일하거나, 마지막 인자로 Throwable을 받을 수 있음.
    public String fallbackForCallExternalService(Throwable t) {
        // 장애 발생 시 대신 리턴할 값을 정의하거나, 캐시에서 읽어오기 등 대체 로직 수행
        return "Fallback 응답: 외부 서비스 장애로 인한 대체 응답입니다.";
    }
}

위의 예시처럼 애노테이션과 YAML 파일 설정만으로 서킷 브레이커가 동작합니다.
문제가 발생할 경우 callExternalService()에서 예외가 던져지거나 시간이 오래 걸리면, 오류율이 계산되어 임계치에 도달 시 회로가 Open 상태가 됩니다. 이후 일정 시간이 지나면 Half-Open으로 테스트를 진행하고, 성공 시 Closed로 돌아가는 흐름입니다.


6. 서킷 브레이커와 함께 고려할 수 있는 다른 패턴

  1. Retry

    • 특정 횟수만큼 재시도한 후 여전히 실패하면 서킷 브레이커를 열도록 할 수 있습니다.
  2. Fallback

    • 서킷 브레이커가 열렸을 때, 호출을 차단하는 대신 대체 응답을 반환하거나, 캐시에서 값을 가져오는 등의 방식을 사용할 수 있습니다.
  3. Bulkhead

    • 대형 선박의 ‘격벽’처럼, 한 서비스의 리소스 사용이 전체 시스템에 영향을 주지 않도록 쓰레드 풀 등을 격리하는 패턴입니다.
  1. Rate Limiter

    • 부하가 갑자기 몰려서 장애가 발생하지 않도록, 요청 양을 제한(Throttle)하는 패턴입니다.
profile
항상 다같이, 즐겁게 일할 수 있으면 좋겠습니다 😎

0개의 댓글