Circuit Breaker 아키텍처 개요

Circuit Breaker는 전기 회로의 서킷 브레이커처럼, 서비스 간 호출에서 장애가 반복될 때 서킷(회로)을 "열어(Open)" 더 이상 장애 위험이 있는 서비스 호출을 차단하고, 일정 시간이 지난 후에 제한적으로 호출을 다시 허용하는 방식으로 시스템 과부하와 장애 확산을 방지하는 패턴입니다.
- Closed(닫힘): 정상 상태로 모든 요청이 서비스로 전달됨.
- Open(열림): 지정한 실패율 임계치를 초과하면 서킷을 열어 서비스 호출 차단.
- Half-Open(반열림): 일정 시간 후 일부 요청을 시도해 장애 복구 여부 확인.
Circuit Breaker 주요 기능과 설정 파라미터
Resilience4j Circuit Breaker 주요 기능 및 설정 파라미터 하나하나에 대해 상세히 설명드리겠습니다.
1. slidingWindowType

- 슬라이딩 윈도우 방식으로 실패율을 계산하는 기준입니다.
- COUNT_BASED: 최근 호출 횟수 기준으로 윈도우 크기를 정함. 예를 들어, 최근 10번 호출 결과로 실패율 계산.
- TIME_BASED: 최근 일정 시간(예: 1분) 동안의 호출 결과로 실패율 계산.
2. slidingWindowSize

- 슬라이딩 윈도우 크기입니다.
- COUNT_BASED일 경우, 최근 몇 번의 호출에 대해 실패율과 상태 변화를 판단할지 결정합니다.
- 예: 10으로 설정 시, 최신 10회 호출 결과만 보고 실패율을 계산합니다.
3. failureRateThreshold

- 실패율의 임계값(%)을 의미합니다.
- 슬라이딩 윈도우에서 계산된 실패율이 이 값 이상이면 서킷브레이커가 OPEN 상태로 전환되어 더 이상 해당 서비스 호출을 막습니다.
- 예: 70%로 설정하면, 10회 중 7회 이상 실패 시 서킷이 열립니다.
4. minimumNumberOfCalls

- Circuit Breaker가 상태를 판단하기 위해 최소한으로 필요한 호출 수입니다.
- 이 수만큼 호출이 누적되기 전까지는 서킷브레이커가 CLOSE 상태를 유지해 정상 동작으로 간주합니다.
- 호출 수가 적을 때 너무 빠른 상태 전환으로 인한 오작동 방지용입니다.
5. waitDurationInOpenState

- 서킷브레이커가 OPEN 상태에 있을 때, 다음 상태인 HALF_OPEN 상태 전환을 위해 기다리는 시간입니다.
- 보통 일정 시간 동안 장애 상태를 유지하다가, 일정 시간이 지나면 장애가 해소되었는지 테스트 차원에서 일부 호출을 허용합니다.
- 예: 10초로 설정하면 OPEN 상태로 10초 동안 유지 후 HALF_OPEN 상태로 변경 시도.
6. permittedNumberOfCallsInHalfOpenState

- HALF_OPEN 상태에서 허용할 최대 호출 수입니다.
- 이 수만큼 호출을 시험용으로 허용하여 성공률을 평가합니다.
- 이 호출들이 성공하면 서킷브레이커는 CLOSE 상태로 복귀하고, 실패 시 다시 OPEN 상태로 돌아갑니다.
7. automaticTransitionFromOpenToHalfOpenEnabled
- OPEN 상태에서 자동으로 HALF_OPEN 상태로 전환할지 여부입니다.
- true로 설정하면, waitDurationInOpenState 시간이 지나면 자동으로 전환됩니다.
- false는 수동 전환 또는 외부 이벤트에 의해 상태 전환을 할 때 사용.
추가 중요한 설정
- slowCallDurationThreshold
- 호출이 이 시간 이상 걸리면, ‘느린 호출(slow call)’로 간주합니다.
- 예: 3000ms (3초) 이상 걸리면 실패처럼 판단할 수 있습니다.
- slowCallRateThreshold
- 슬라이딩 윈도우 내 ‘느린 호출’ 비율 임계값(%)입니다.
- 이 비율 이상이면 서킷브레이커가 OPEN 상태로 전환될 수 있습니다.
- recordExceptions
- 장애로 기록할 예외를 지정합니다. 지정한 예외가 발생하면 호출 실패로 기록됩니다.
- ignoreExceptions
- 실패로 간주하지 않을 예외입니다. 이 예외가 발생해도 호출 성공으로 간주합니다.
- eventConsumerBufferSize
- 내부적으로 상태 변경 등 이벤트를 저장하는 버퍼 크기입니다. Actuator 등에서 이벤트 모니터링 시 활용됩니다.
Gradle 의존성 설정 방법
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-aop'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'io.github.resilience4j:resilience4j-spring-boot2:1.7.0'
implementation 'io.github.resilience4j:resilience4j-all:1.7.0'
// 선택적으로 각 패턴별 모듈(resilience4j-circuitbreaker, resilience4j-retry, 등)만 추가해도 됨
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
- 최신 버전은 공식 문서에 따라 변경될 수 있음.
Introduction
Resilience4j is a lightweight fault tolerance library designed for functional programming. Resilience4j provides higher-order functions (decorators) to enhance any functional interface, lambda expression or method reference with a Circuit Breaker, Rate Lim
resilience4j.readme.io
예시 YAML 설정 (application.yml)
resilience4j.circuitbreaker:
configs:
default:
slidingWindowType: COUNT_BASED
minimumNumberOfCalls: 7
slidingWindowSize: 10
waitDurationInOpenState: 10s
failureRateThreshold: 40
slowCallDurationThreshold: 3000
slowCallRateThreshold: 60
permittedNumberOfCallsInHalfOpenState: 5
automaticTransitionFromOpenToHalfOpenEnabled: true
eventConsumerBufferSize: 10
recordExceptions:
- com.example.resilience4jdemo.exception.RecordException
ignoreExceptions:
- com.example.resilience4jdemo.exception.IgnoreException
instances:
simpleCircuitBreakerConfig:
baseConfig: default
management.endpoints.web.exposure.include: '*'
management.endpoint.health.show-details: always
management.health.diskspace.enabled: false
management.health.circuitbreakers.enabled: true
management.metrics.tags.application: ${spring.application.name}
management.metrics.distribution.percentiles-histogram.http.server.requests: true
management.metrics.distribution.percentiles-histogram.resilience4j.circuitbreaker.calls: true
주요 파라미터 설명
- minimumNumberOfCalls: 7 → 최소 7번 호출은 무조건 정상 호출로 간주(초기 데이터 부정확성 보완).
- slidingWindowSize: 10 → 이후 최신 10회 호출 기록으로 실패율 계산.
- failureRateThreshold: 40 → 실패율 40% 이상 시 서킷 열림(Open).
- waitDurationInOpenState: 10s → Open 상태에서 10초 기다렸다가 Half-Open 시도.
- permittedNumberOfCallsInHalfOpenState: 5 → Half-Open 상태 시 5번 재시도 후 상태 결정.
- automaticTransitionFromOpenToHalfOpenEnabled: true → 자동으로 Open → Half-Open 상태 전환.
- recordExceptions 및 ignoreExceptions → 어떤 예외를 실패로 기록할지, 무시할지를 정함.
CircuitBreaker 서비스 예제 코드
@Slf4j
@Service
public class CircuitBreakerService {
private static final String SIMPLE_CIRCUIT_BREAKER_CONFIG = "simpleCircuitBreakerConfig";
@CircuitBreaker(name = SIMPLE_CIRCUIT_BREAKER_CONFIG, fallbackMethod = "fallback")
public String process(String param) throws InterruptedException {
return callAnotherServer(param);
}
// 예외 유형에 따른 개별 fallback 처리
private String fallback(String param, RecordException ex) {
log.info("RecordException fallback! your request is " + param);
return "Recovered: " + ex.toString();
}
private String fallback(String param, IgnoreException ex) {
log.info("IgnoreException fallback! your request is " + param);
return "Recovered: " + ex.toString();
}
private String fallback(String param, CallNotPermittedException ex) {
log.info("CallNotPermittedException fallback! your request is " + param);
return "Recovered: " + ex.toString();
}
private String callAnotherServer(String param) throws InterruptedException {
if ("a".equals(param))
throw new RecordException("record exception");
else if ("b".equals(param))
throw new IgnoreException("ignore exception");
else if ("c".equals(param)) // 3초 이상 걸리는 경우도 실패로 간주 (slow call)
Thread.sleep(4000);
return param;
}
}


Spring Actuator와 연동

- Actuator를 통해 Circuit Breaker 상태, 호출 통계, 이벤트 등을 실시간 모니터링할 수 있습니다.
- Actuator 설정에서 management.health.circuitbreakers.enabled를 true로 활성화하면 /actuator/health/circuitbreakers 엔드포인트에서 상태 확인 가능.
- /actuator/circuitbreakers에서 서킷 브레이커 관련 메트릭과 상태들을 상세하게 노출합니다.
- 이와 함께 메트릭(histogram, percentile)도 활성화하여 퍼포먼스 모니터링 강화.
Resilience4j Circuit Breaker와 스프링 Actuator 통합 실습
Actuator 관련 설정 활성화 (application.yml)
먼저 Actuator 엔드포인트들을 활성화하여 Circuit Breaker 관련 상태 및 제어가 가능하도록 설정합니다.
management.endpoints.web.exposure.include: '*'
management.endpoint.health.show-details: always
management.health.circuitbreakers.enabled: true
management.health.diskspace.enabled: false
management.metrics.tags.application: ${spring.application.name}
management.metrics.distribution.percentiles-histogram.http.server.requests: true
management.metrics.distribution.percentiles-histogram.resilience4j.circuitbreaker.calls: true
Circuit Breaker 인스턴스 및 설정 정의 (application.yml)
resilience4j.circuitbreaker:
configs:
default:
slidingWindowType: COUNT_BASED
minimumNumberOfCalls: 7 # 최소 7번까지는 무조건 CLOSE로 가정하고 호출한다.
slidingWindowSize: 10 # (minimumNumberOfCalls 이후로는) 10개의 요청을 기준으로 판단한다.
waitDurationInOpenState: 10s # OPEN 상태에서 HALF_OPEN으로 가려면 얼마나 기다릴 것인가?
failureRateThreshold: 40 # slidingWindowSize 중 몇 %가 recordException이면 OPEN으로 만들 것인가?
slowCallDurationThreshold: 3000 # 몇 ms 동안 요청이 처리되지 않으면 실패로 간주할 것인가?
slowCallRateThreshold: 60 # slidingWindowSize 중 몇 %가 slowCall이면 OPEN으로 만들 것인가?
permittedNumberOfCallsInHalfOpenState: 5 # HALF_OPEN 상태에서 5번까지는 CLOSE로 가기위해 호출한다.
automaticTransitionFromOpenToHalfOpenEnabled: true # OPEN 상태에서 자동으로 HALF_OPEN으로 갈 것인가?
eventConsumerBufferSize: 10 # actuator를 위한 이벤트 버퍼 사이즈
recordExceptions:
- com.example.resilience4jdemo.exception.RecordException
ignoreExceptions:
- com.example.resilience4jdemo.exception.IgnoreException
instances:
simpleCircuitBreakerConfig:
baseConfig: default
Resilience4j Circuit Breaker 설정을 작성해 인스턴스와 상세 파라미터를 지정합니다.
서비스 코드에 @CircuitBreaker 적용
package com.example.resilience4jdemo.e_circuitbreaker_fallback;
import com.example.resilience4jdemo.exception.IgnoreException;
import com.example.resilience4jdemo.exception.RecordException;
import io.github.resilience4j.circuitbreaker.CallNotPermittedException;
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class CircuitBreakerService {
private static final String SIMPLE_CIRCUIT_BREAKER_CONFIG = "simpleCircuitBreakerConfig";
@CircuitBreaker(name = SIMPLE_CIRCUIT_BREAKER_CONFIG, fallbackMethod = "fallback")
public String process(String param) throws InterruptedException {
return callAnotherServer(param);
}
private String fallback(String param, RecordException ex) {
log.info("RecordException fallback! your request is " + param);
return "Recovered: " + ex.toString();
}
private String fallback(String param, IgnoreException ex) {
log.info("IgnoreException fallback! your request is " + param);
return "Recovered: " + ex.toString();
}
private String fallback(String param, CallNotPermittedException ex) {
log.info("CallNotPermittedException fallback! your request is " + param);
return "Recovered: " + ex.toString();
}
private String callAnotherServer(String param) throws InterruptedException {
if ("a".equals(param))
throw new RecordException("record exception");
else if ("b".equals(param))
throw new IgnoreException("ignore exception");
else if ("c".equals(param)) // 3초 이상 걸리는 경우도 실패로 간주
Thread.sleep(4000);
return param;
}
};
Circuit Breaker를 적용할 메소드에 어노테이션과 fallback 메소드를 구현합니다.
1. 서킷브레이커 목록 조회

- 애플리케이션에 정의된 모든 Circuit Breaker 인스턴스의 이름 목록을 확인합니다.
- HTTP 요청: GET <http://localhost:8080/actuator/circuitbreakers>
- 이 엔드포인트는 현재 애플리케이션에서 관리 중인 Circuit Breaker 이름을 리스트 형태로 보여줍니다.
2. 서킷브레이커 상태 강제 변경 (예: OPEN 상태로 강제 전환)

- 개발자나 운영자가 수동으로 Circuit Breaker 상태를 변경하여 테스트하거나 장애 시나리오 시뮬레이션에 활용합니다.
- HTTP 요청: POST <http://localhost:8080/actuator/circuitbreakers/{circuitBreakerName}>
- 요청 바디(JSON 예시):
- FORCE_OPEN: 강제로 서킷을 열어 호출 차단
- FORCE_CLOSED: 강제로 서킷을 닫아 호출 허용
- CLOSED, OPEN, HALF_OPEN 등의 상태도 직접 지정 가능
- 이 명령을 보내면 해당 Circuit Breaker가 즉시 지정한 상태로 변경되어 동작하며, 서비스 호출 흐름에도 즉각적 영향을 줍니다.
- 만약에 open으로 설정시, 자동으로 half open 되지 않습니다.
반응형
'System Engineering > Spring Boot java (스프링 부트 자바)' 카테고리의 다른 글
| [Resilience4j] 장애 허용성을 위한 라이브러리 소개와 사용법 (자바 스프링 부트) (0) | 2025.08.21 |
|---|---|
| [Spring Boot] Record 객체를 이용하여 DTO 작성 (1) | 2025.01.25 |
| [Spring] 스프링 MVC 예외 처리 시 인터셉터 재호출 해결법 (1) | 2024.08.09 |
| [Spring] 서블릿 예외 처리 시 필터 재호출 해결법 (1) | 2024.07.28 |
| [Spring] 서블릿 예외 처리와 오류 페이지 (0) | 2024.07.28 |
댓글