2025. 3. 16. 14:48ㆍSpring Microservice
🚀 [Spring Cloud] Resilience4j Circuit Breaker 구현 가이드
마이크로서비스는 네트워크로 연결된 다양한 원격 서비스와 지속적인 상호작용을 하며 운영됩니다. 이런 환경에서 하나의 서비스 장애가 전체 시스템으로 전파되는 걸 막는 핵심 전략이 바로 서킷 브레이커(Circuit Breaker)입니다. 이번 글에서는 Spring Cloud 환경에서 Resilience4j를 통해 서킷 브레이커 패턴을 어떻게 정확히 구현하는지 모든 개념과 예제를 철저히 분석하며 살펴보겠습니다.
📌 1. 서킷 브레이커(Circuit Breaker) 개념 이해하기
서킷 브레이커의 작동 원리는 전기 회로에서 사용하는 차단기와 같습니다. 전기 시스템에서 과전류가 흐르면 차단기가 즉시 전류를 차단해 시스템을 보호하듯, 소프트웨어 서킷 브레이커는 원격 서비스가 실패하거나 응답 시간이 느릴 때 호출을 빠르게 중단하여 시스템 전체가 장애로 확산되는 것을 막습니다. 🔌🛡️
Resilience4j는 다음과 같이 3가지 상태로 구성된 유한 상태 머신(Finite State Machine)를 통해 서킷 브레이커를 관리합니다.
🔍 Resilience4j 서킷 브레이커의 상태 전이 다이어그램

- Closed 상태 🔒
- 모든 요청이 정상적으로 수행되는 상태입니다.
- 호출 결과(성공 0, 실패 1)를 링 비트 버퍼(Ring Bit Buffer)에 기록합니다.
- 실패율이 설정된 임계값(threshold)을 넘으면 Open 상태로 전환됩니다.
- Open 상태 🔓
- 모든 호출을 즉시 실패 처리하며
CallNotPermittedException
예외를 발생시킵니다. - 미리 정해진 시간(
waitDurationInOpenState
) 이후 Half-open 상태로 전환됩니다.
- 모든 호출을 즉시 실패 처리하며
- Half-open 상태 🚪
- 일부 호출을 허용하여 서비스가 복구됐는지 점검합니다.
- 새롭게 계산된 실패율이 기준을 초과하면 다시 Open 상태로 전환됩니다.
- 실패율이 안정적이라면 Closed 상태로 다시 전환됩니다.
📌 2. 링 비트 버퍼(Ring Bit Buffer)란 무엇인가?
서킷 브레이커는 호출의 성공과 실패를 판단하기 위해 링 비트 버퍼라는 특수한 데이터 구조를 사용합니다.

- 성공한 요청은 0, 실패한 요청은 1로 기록됩니다.
- 버퍼가 가득 찰 때까지는 실패율을 계산하지 않습니다.
- 위 그림처럼 12개의 요청이 기록된 이후 실패율이 설정된 임계값을 초과해야만 서킷 브레이커가 Open 상태로 전환됩니다.
즉, 충분한 데이터가 모이기 전까지는 무작정 Open 상태로 전환되지 않습니다.
📌 3. 실제 코드로 보는 서킷 브레이커 적용하기
🎯 데이터베이스 및 서비스 호출에 Resilience4j 적용하기
다음은 Resilience4j를 사용하여 두 가지 유형의 원격 자원을 보호하는 실제 예제입니다.

위 그림은 애플리케이션 A와 B가 Licensing 서비스를 호출하고, Licensing 서비스가 데이터베이스 및 Organization 서비스와 통신하는 환경을 나타냅니다.
이때 Resilience4j는 두 가지 호출을 모두 보호하고 있습니다.
- 🔸 첫 번째 카테고리(좌측): Licensing 서비스가 데이터베이스 호출을 수행할 때, 이 호출을 서킷 브레이커로 보호합니다.
- 🔸 두 번째 카테고리: 마이크로서비스 간(interservice) 호출을 서킷 브레이커로 보호합니다.
Licensing 서비스는 다시 Organization 서비스를 호출하는데, 이 서비스 간 호출 역시 Resilience4j 서킷 브레이커로 보호됩니다.
이처럼 Resilience4j는 데이터베이스나 REST 기반 서비스 호출 등 원격 자원의 종류에 관계없이 모든 호출을 똑같은 방식으로 보호할 수 있습니다.
서킷 브레이커를 적용하는 방법은 아주 간단합니다. 메서드 위에 다음과 같은 간단한 어노테이션 하나만 붙이면 됩니다.
✅ LicenseService.java 예제 코드
@CircuitBreaker(name = "licenseService")
public List<License> getLicensesByOrganization(String organizationId) {
return licenseRepository.findByOrganizationId(organizationId);
}
- 위 코드의
@CircuitBreaker
어노테이션은 Spring이 자동으로 프록시를 만들어 메서드 호출을 관리하도록 합니다. - 서킷 브레이커가 활성화되면 호출이 실패했을 때 즉시 차단합니다.
📌 4. 장애 허용 시스템 시뮬레이션을 통한 실제 작동 원리 확인
정상 상황에서는 서킷 브레이커 작동이 눈에 띄지 않기 때문에, 다음과 같은 지연 코드를 추가해 직접 장애를 유도할 수 있습니다.
✅ LicenseService.java에 장애 유도 코드 추가
private void randomlyRunLong(){
Random rand = new Random();
int randomNum = rand.nextInt(3) + 1;
if (randomNum == 3) sleep();
}
private void sleep(){
try {
Thread.sleep(5000); // 5초 대기 후 TimeoutException 발생
throw new java.util.concurrent.TimeoutException();
} catch (InterruptedException e) {
logger.error(e.getMessage());
}
}
@CircuitBreaker(name = "licenseService")
public List<License> getLicensesByOrganization(String organizationId) {
randomlyRunLong();
return licenseRepository.findByOrganizationId(organizationId);
}
- 위 엔드포인트를 반복적으로 호출하면 결국 서킷 브레이커의 링 비트 버퍼가 가득 차면서, Open 상태로 전환됩니다.
- 이때 Postman에서 다음과 같은 에러 응답이 발생합니다.
🚨 서킷 브레이커 활성화 시 실제 에러 응답 (Postman 화면)

📌 5. Resilience4j 서킷 브레이커 커스터마이징 설정하기
디폴트값만으로 충분하지 않다면, 다음과 같이 더 세밀한 설정이 가능합니다.
✅ bootstrap.yml에 서킷 브레이커 세부 설정 추가 예시
resilience4j.circuitbreaker:
instances:
licenseService:
registerHealthIndicator: true
ringBufferSizeInClosedState: 5
ringBufferSizeInHalfOpenState: 3
waitDurationInOpenState: 10s
failureRateThreshold: 50
recordExceptions:
- org.springframework.web.client.HttpServerErrorException
- java.io.IOException
- java.util.concurrent.TimeoutException
- org.springframework.web.client.ResourceAccessException
organizationService:
registerHealthIndicator: true
ringBufferSizeInClosedState: 6
ringBufferSizeInHalfOpenState: 4
waitDurationInOpenState: 20s
failureRateThreshold: 60
🔖 resilience4j.circuitbreaker.instances.licenseService 설정
resilience4j.circuitbreaker:
instances:
licenseService:
resilience4j.circuitbreaker.instances.licenseService 설정 값은 @CircuitBreaker(name = "licenseService") 어노테이션를 통해 서킷 브레이커에게 제공된 이름입니다.
📖 각 설정값의 의미
옵션 | 설명 | 디폴트 값 |
---|---|---|
registerHealthIndicator | Spring Boot Actuator의 health 엔드포인트에 서킷 브레이커의 상태 정보를 노출할 것인지 여부를 설정 | true |
ringBufferSizeInClosedState | CLOSED 상태에서 버퍼 크기 (호출 수) | 100 |
ringBufferSizeInHalfOpenState | HALF-OPEN 상태에서 호출 수 | 10 |
waitDurationInOpenState | OPEN 상태 유지 시간 (지정 후 HALF-OPEN 전환) | 60초 |
failureRateThreshold | OPEN 상태로 전환되는 실패율 기준 | 50% |
recordExceptions | 실패로 간주할 예외 지정 목록 | 모든 예외 기록 (디폴트) |
🚦 6. 특수 서킷 브레이커 상태: DISABLED와 FORCED_OPEN 완벽 정리
Resilience4j의 서킷 브레이커는 디폴트로 아래의 상태를 순환하면서 동작합니다.
- CLOSED → OPEN → HALF_OPEN
하지만 때로는 정상적인 흐름과 다른 특수한 상황이 필요할 때가 있습니다. Resilience4j는 이를 위해 두 가지 추가적인 특수 상태를 제공합니다.
🚩 특수 상태 1: DISABLED
🔍 DISABLED 상태란?
DISABLED 상태는 서킷 브레이커의 모든 기능을 일시적으로 비활성화하고, 호출을 항상 허용하도록 설정합니다.
✅ 언제 사용해야 할까?
- 서킷 브레이커를 잠시 비활성화하고 모든 요청이 항상 성공적으로 수행되어야 하는 상황에서 사용합니다.
- 장애 상황에서 일시적으로 우회 조치를 취하고, 서킷 브레이커가 장애 판단을 하지 않도록 해야 하는 상황에서 유용합니다.
- 테스트 또는 디버깅 과정에서 서킷 브레이커의 영향을 제거하고자 할 때 효과적으로 사용됩니다.
🔧 사용 예시 (구체적인 설정법)
resilience4j.circuitbreaker:
instances:
licenseService:
state: DISABLED # 👈 서킷 브레이커를 비활성화 상태로 변경
이렇게 설정하면, 모든 호출이 항상 허용되고 서킷 브레이커는 상태 전환이나 장애 처리를 수행하지 않습니다.
🚩 특수 상태 2: FORCED_OPEN
🔍 FORCED_OPEN 상태란?
FORCED_OPEN 상태는 서킷 브레이커를 강제로 항상 열려있는 상태(OPEN) 로 설정하여 모든 호출을 즉시 차단합니다.
✅ 언제 사용해야 할까?
- 서비스가 긴급한 장애 상태이고, 즉각적으로 모든 원격 서비스 호출을 중단해야 하는 긴급 상황에서 사용합니다.
- 서비스가 긴급 유지보수 상태로 들어갈 때, 즉시 모든 호출을 차단해 시스템 보호를 하고자 할 때 사용됩니다.
- 의도적으로 모든 원격 호출을 중단하여 장애 상황을 강제로 시뮬레이션하거나 테스트할 때 사용됩니다.
🔧 사용 예시 (구체적인 설정법)
resilience4j.circuitbreaker:
instances:
licenseService:
state: FORCED_OPEN # 👈 강제로 OPEN 상태로 전환
이 설정을 적용하면 모든 호출이 즉시 실패하며, 아래와 같은 예외를 던지게 됩니다.
{
"message": "CircuitBreaker 'licenseService' is FORCED_OPEN and does not permit further calls",
"detail": "CircuitBreaker 'licenseService' is FORCED_OPEN and does not permit further calls"
}
🎯 특수 상태 간단 비교 표 정리
상태 이름 동작 방식 사용 시나리오 상태 유지 여부
✅ DISABLED | 모든 호출 허용 | 테스트, 디버깅, 긴급 우회 상황 | 수동으로 해제 |
🚫 FORCED_OPEN | 모든 호출 즉시 실패 처리 | 긴급 유지보수, 긴급 장애 차단, 장애 상황 테스트 시뮬레이션 | 수동으로 해제 |
⚠️ 특수 상태를 사용할 때 주의할 점
- 이 두 가지 상태는 정상적인 상태 전환(CLOSED ↔ OPEN ↔ HALF-OPEN)을 하지 않고, 수동적으로 설정하고 해제 해야 합니다.
- 운영환경에서 설정 시, 운영 중단을 초래할 수 있으므로 각별한 주의가 필요합니다.
- 서비스 운영 상태를 모니터링하여, 장애 상황이나 테스트가 끝나면 다시 원래 상태로 되돌리는 것을 잊지 마세요.
🎯 정리 및 마무리
서킷 브레이커를 제대로 활용하면 마이크로서비스의 안정성을 극대화할 수 있습니다. Resilience4j는 아주 간편하면서도 강력한 설정과 기능을 제공하여, 복잡한 시스템에서도 장애로부터 안정적으로 시스템을 보호할 수 있게 해줍니다.
이번 포스팅으로 Resilience4j의 서킷 브레이커 패턴을 정확히 이해하고 완벽하게 구현하는 데 도움이 되셨기를 바랍니다. 다음 포스팅에서는 더욱 다양한 실습과 고급 사용법을 소개하겠습니다. 감사합니다! 🚀🌟
'Spring Microservice' 카테고리의 다른 글
Implementing the bulkhead pattern (1) | 2025.03.16 |
---|---|
Fallback processing (0) | 2025.03.16 |
Spring Cloud와 Resilience4j를 사용하기 위한 라이센싱 서비스 설정 (0) | 2025.03.16 |
Implementing Resilience4j (0) | 2025.03.16 |
클라이언트 회복성이 중요한 이유 (0) | 2025.03.16 |