실무에 바로 쓰는 DDD기반으로 유연성과 확정성 있게 MSA 설계하기
서킷 브레이커
서킷 브레이커
- 서킷 브레이커
- 서킷 브레이커(Circuit Breaker)란?
- 서킷 브레이커가 필요한 이유
- 서킷 브레이커의 핵심 개념
- 서킷 브레이커 상태 변화
- MSA 환경에서 Circuit Breaker 구조
- Resilience4j
- 의존성 추가
- Gateway Circuit Breaker 설정
- resilience4j 설정
- 설정 값 의미
- OrderServiceClient 구현
- @CircuitBreaker 의미
- fallbackMethod
- fallback의 중요성
- Circuit Breaker 요청 흐름
- 테스트 코드
- 장애 테스트
- Circuit Breaker의 장점
- Spring Cloud 기반 MSA 전체 구조
- 정리
서킷 브레이커(Circuit Breaker)란?
MSA 환경에서는 서비스 간 호출이 매우 빈번하게 발생한다.
예를 들어:
- 주문 서비스 → 결제 서비스 호출
- 주문 서비스 → 메뉴 서비스 호출
- 배송 서비스 → 주문 서비스 호출
이때 특정 서비스가 장애 상태인데도 계속 요청을 보내면 장애가 전체 시스템으로 전파될 수 있다.
이 문제를 해결하기 위해 사용하는 패턴이 바로 Circuit Breaker(서킷 브레이커)이다.
서킷 브레이커가 필요한 이유
MSA 환경에서는 서비스 간 네트워크 호출이 많아진다.
예를 들어 다음과 같은 상황을 생각해보자.
Client → Gateway → Order Service → Menu Service
여기서 Menu Service가 장애 상태인데도 Order Service가 계속 요청을 보내면:
- 응답 지연 증가
- 스레드 점유 증가
- 타임아웃 발생
- 전체 서비스 장애 전파
문제가 발생할 수 있다.
즉,
하나의 서비스 장애가 전체 시스템 장애로 확산될 수 있다
서킷 브레이커의 핵심 개념
서킷 브레이커는 전기 차단기와 비슷한 개념이다.
정상 상태에서는 요청을 전달하지만, 장애가 일정 수준 이상 발생하면 회로를 차단(Open)하여 추가 요청을 막는다.
서킷 브레이커 상태 변화
stateDiagram-v2
[*] --> CLOSED
CLOSED --> OPEN : 실패율 증가
OPEN --> HALF_OPEN : 일정 시간 후
HALF_OPEN --> CLOSED : 정상 응답
HALF_OPEN --> OPEN : 다시 실패
CLOSED 상태
정상 상태이다.
- 요청 정상 전달
- 서비스 호출 가능
OPEN 상태
장애 상태이다.
- 요청 차단
- fallback 실행
- 대상 서비스 호출 중단
HALF_OPEN 상태
복구 확인 단계이다.
- 일부 요청만 허용
- 정상 여부 테스트
MSA 환경에서 Circuit Breaker 구조
flowchart LR
Client[Client]
Gateway[API Gateway]
Order[Order Service]
Menu[Menu Service]
CB[Circuit Breaker]
Client --> Gateway
Gateway --> Order
Order --> CB
CB --> Menu
여기서 핵심은:
- 실제 서비스 호출 전에 Circuit Breaker가 중간에서 상태를 관리
- 장애 발생 시 호출 차단 가능
이라는 점이다.
Resilience4j
Resilience4j는 Spring Cloud 환경에서 많이 사용하는 장애 대응 라이브러리이다.
MSA 환경에서:
- Circuit Breaker
- Retry
- Timeout
- Rate Limiter
등을 쉽게 구현할 수 있다.
의존성 추가
Resilience4j Circuit Breaker
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>
Reactor Resilience4j
WebFlux 환경에서 사용하는 의존성이다.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
</dependency>
Gateway Circuit Breaker 설정
server:
port: 8080
spring:
cloud:
gateway:
routes:
- id: order-service
uri: http://localhost:8082
predicates:
- Path=/orders/**
- id: menu-service
uri: http://localhost:8081
predicates:
- Path=/menus/**
resilience4j 설정
resilience4j:
circuitbreaker:
instances:
myCircuitBreaker:
register-health-indicator: true
sliding-window-type: COUNT_BASED
sliding-window-size: 5
minimum-number-of-calls: 5
failure-rate-threshold: 50
wait-duration-in-open-state: 10s
permitted-number-of-calls-in-half-open-state: 2
설정 값 의미
sliding-window-size
sliding-window-size: 5
최근 5개의 요청을 기준으로 실패율 계산
failure-rate-threshold
failure-rate-threshold: 50
실패율이 50%를 넘으면 OPEN 상태 전환
wait-duration-in-open-state
wait-duration-in-open-state: 10s
OPEN 상태 유지 시간
10초 후 HALF_OPEN 상태로 변경
permitted-number-of-calls-in-half-open-state
permitted-number-of-calls-in-half-open-state: 2
HALF_OPEN 상태에서 테스트 요청 허용 개수
OrderServiceClient 구현
@Service
public class OrderServiceClient {
private final WebClient webClient;
public OrderServiceClient(WebClient.Builder webClientBuilder) {
this.webClient =
webClientBuilder.baseUrl("http://localhost:8082").build();
}
@CircuitBreaker(
name = "orderServiceCb",
fallbackMethod = "fallbackOrders"
)
public Mono<String> getOrders() {
return webClient.get()
.uri("/orders")
.retrieve()
.bodyToMono(String.class);
}
public Mono<String> fallbackOrders(Throwable t) {
return Mono.just(
"Orders Service is currently unavailable."
);
}
}
@CircuitBreaker 의미
@CircuitBreaker(
name = "orderServiceCb",
fallbackMethod = "fallbackOrders"
)
해당 메서드 호출에 Circuit Breaker를 적용한다.
fallbackMethod
서비스 장애 발생 시 대신 실행되는 메서드이다.
즉:
- 실제 서비스 호출 실패
- fallback 메서드 실행
- 기본 응답 반환
구조이다.
fallback의 중요성
fallback은 사용자 경험 측면에서 매우 중요하다.
예를 들어 주문 서비스 장애 시:
500 Internal Server Error
를 그대로 반환하는 대신:
현재 주문 서비스를 사용할 수 없습니다.
잠시 후 다시 시도해주세요.
같은 대체 응답을 제공할 수 있다.
Circuit Breaker 요청 흐름
sequenceDiagram
participant Client
participant Gateway
participant CB as Circuit Breaker
participant Order as Order Service
Client->>Gateway: 요청
Gateway->>CB: 서비스 호출
alt 서비스 정상
CB->>Order: 요청 전달
Order-->>CB: 응답
CB-->>Gateway: 정상 응답
else 서비스 장애
CB-->>Gateway: fallback 응답
end
Gateway-->>Client: 최종 응답
테스트 코드
예시:
StepVerifier.create(result)
.expectNext(mockResponse)
.verifyComplete();
장애 테스트
.thenReturn(
Mono.error(
new RuntimeException("Simulated Error")
)
);
이를 통해 fallback 동작을 검증할 수 있다.
Circuit Breaker의 장점
장애 전파 방지
하나의 서비스 장애가 전체로 확산되는 것을 막는다.
빠른 실패(Fail Fast)
불필요한 대기 시간을 줄인다.
복원력 향상
서비스 장애 상황에서도 최소 기능 유지 가능
사용자 경험 개선
fallback 응답 제공 가능
Spring Cloud 기반 MSA 전체 구조
flowchart TD
Client[IoT / Mobile / Browser]
Gateway[API Gateway]
Menu[Menus Service]
Order[Orders Service]
Config[Config Server]
Eureka[Service Registry]
Circuit[Circuit Breaker Dashboard]
Sleuth[Spring Cloud Sleuth]
Metrics[Metrics Store]
DB[(Databases)]
MQ[(Message Brokers)]
Client --> Gateway
Gateway --> Menu
Gateway --> Order
Menu --> DB
Order --> DB
Menu --> MQ
Order --> MQ
Menu --> Metrics
Order --> Metrics
Menu --> Eureka
Order --> Eureka
Menu --> Config
Order --> Config
정리
Circuit Breaker는 MSA 환경에서 장애 전파를 막고 시스템 복원력을 높이기 위한 핵심 패턴이다.
서비스 장애 발생 시 호출을 차단하고 fallback 응답을 제공함으로써 전체 시스템 안정성을 높일 수 있다.
Resilience4j를 활용하면 Spring Cloud 환경에서도 쉽게 Circuit Breaker를 구현할 수 있다.
한 줄 요약
Circuit Breaker는 MSA 환경에서 특정 서비스 장애가 전체 시스템으로 확산되는 것을 방지하기 위해 실패율 기반으로 서비스 호출을 차단하고 fallback 응답을 제공하는 장애 대응 패턴이다.