
개요
도대체 서킷 브레이커가 무엇이고 이걸 왜 쓰는 걸까요...?
마이크로서비스 아키텍처에서 서비스 간의 장애 전파를 막기 위한 패턴이라고 하는데...
오늘은 같이 공부하며 서킷 브레이커를 왜 사용해야 하는지에 대한 이해와 간단하게 적용을 한 번 해보고자 합니다.

1. 서킷 브레이커의 탄생 배경
서킷 브레이커는 전기 회로에서 과부하를 방지하기 위한 장치에서 이름을 따왔습니다.

마이크로서비스 아키텍처가 대두되면서 서비스들이 분산되고, 서로 다른 네트워크 환경에서 통신하게 되었습니다.
하지만 네트워크 지연이나 장애로 인해 하나의 서비스 장애가 다른 서비스로 전파되어 전체 시스템의 안정성을 해치는
문제가 발생했습니다.
이러한 문제를 해결하기 위해 마틴 파울러는 서킷 브레이커 패턴을 제안했습니다. 이는 서비스 간의 호출에서 장애가 발생했을 때,
빠르게 오류를 반환하고 장애 복구 시까지 호출을 막는 역할을 합니다.
2. 서킷 브레이커의 주요 구성 요소
서킷 브레이커는 세 가지 주요 상태와 구성 요소로 이루어져 있습니다.
- Closed 상태: 평상시 상태로, 요청을 정상적으로 전달합니다.
- Open 상태: 연속적인 실패로 인해 회로가 열려 더 이상 요청을 전달하지 않습니다.
- Half-Open 상태: 일정 시간 후에 회로를 부분적으로 열어 일부 요청을 전달해 봅니다.
또한 다음과 같은 구성 요소가 있습니다.
- 실패 카운터: 연속적인 실패 횟수를 기록합니다.
- 타임아웃 설정: Open 상태에서 Half-Open 상태로 전환하기 위한 시간입니다.
- Fallback 처리: 서비스 장애 시 대체 로직을 수행합니다.
3. 서킷 브레이커의 동작 방식
3-1. Closed 상태
- 초기 상태로, 모든 요청은 정상적으로 전달됩니다.
- 요청이 성공하면 실패 카운터를 초기화합니다.
- 일정 횟수 이상의 연속적인 실패가 발생하면 Open 상태로 전환됩니다.
3-2. Open 상태
- 서킷 브레이커가 회로를 열어 요청을 바로 실패 처리합니다.
- 이로써 장애가 발생한 서비스에 불필요한 부하를 주지 않습니다.
- 타임아웃 기간 동안 이 상태를 유지합니다.
3-3. Half-Open 상태
- 타임아웃이 지나면 Half-Open 상태로 전환됩니다.
- 일부 요청을 전달하여 서비스가 복구되었는지 확인합니다.
- 요청이 성공하면 Closed 상태로 돌아가고, 실패하면 다시 Open 상태로 전환됩니다.
4. 서킷 브레이커의 장점
- 장애 전파 방지: 하나의 서비스 장애가 전체 시스템으로 확산되는 것을 막습니다.
- 시스템 안정성 향상: 불필요한 대기 시간과 리소스 소모를 줄여줍니다.
- 빠른 장애 감지 및 복구: 서비스의 상태를 모니터링하여 빠르게 대응합니다.
- 유연한 장애 처리: Fallback 로직을 통해 사용자 경험을 향상시킬 수 있습니다.
5. 서킷 브레이커 간단 예제 적용해보기
직접 서킷 브레이커를 적용하여 성능 개선을 확인해보겠습니다.
5-1. 프로젝트 환경 설정
- 프레임워크: Spring Boot 3.2
- 사용 라이브러리: Resilience4j
5-2. 서킷 브레이커 설정 조정
application.yml 파일에서 서킷 브레이커의 설정을 다음과 같이 구성하였습니다:
resilience4j:
circuitbreaker:
instances:
queueService:
slidingWindowType: COUNT_BASED
slidingWindowSize: 200 # 슬라이딩 윈도우 크기 증가
minimumNumberOfCalls: 150
failureRateThreshold: 80 # Failure Rate Threshold 상향
waitDurationInOpenState: 10s # 대기 시간 단축
permittedNumberOfCallsInHalfOpenState: 20
recordExceptions:
- java.lang.Exception
ignoreExceptions:
- com.example.exception.BusinessException
5-3. 서비스 코드에 서킷 브레이커 적용
QueueService 클래스에 @CircuitBreaker 어노테이션을 사용하여 서킷 브레이커를 적용합니다.
@Slf4j
@Service
@RequiredArgsConstructor
public class QueueService {
private final QueueRepository queueRepository;
@CircuitBreaker(name = "queueService", fallbackMethod = "enterQueueFallback")
@Transactional
public String enterQueue(Long userId) {
// 실제 서비스 로직
}
private String enterQueueFallback(Long userId, Exception e) {
// Fallback 로직 구현
}
}
6. 성능 테스트 실행 및 결과 분석
부하 테스트 도구인 K6를 사용하여 성능 테스트를 진행하였습니다.
- 테스트 시나리오: 최대 150명의 가상 사용자가 대기열 토큰 발급 및 체크 API에 동시 접속
- 테스트 결과:
- 서킷 브레이커 적용 후 평균 응답 시간: 14.74ms
- 처리량 향상: 초당 요청 수 42.02건으로 증가
- 에러율: 0%로 안정적인 서비스 제공
6-1. 결과 분석
- 응답 시간 개선: 서킷 브레이커 적용으로 인해 응답 시간이 크게 단축되어 사용자 경험이 향상되었습니다.
- 시스템 안정성 증가: 서킷 브레이커가 과도한 부하로부터 시스템을 보호하고, 장애 전파를 방지하였습니다.
- 자원 활용 최적화: 불필요한 요청을 차단하여 서버의 CPU 및 메모리 자원 사용량이 감소하였습니다.
7. 서킷 브레이커의 활용 사례
7-1. 콘서트 예약 시스템에서의 적용
콘서트 예약 시스템은 많은 사용자가 동시에 접근하여 예약을 시도하는 환경에서 안정적으로 동작해야 합니다. 서킷 브레이커를 적용하여 다음과 같은 효과를 얻었습니다.
- 장애 격리: 특정 서비스의 장애가 전체 시스템에 영향을 미치지 않도록 격리
- 성능 개선: 응답 시간 단축과 처리량 증가로 사용자 만족도 향상
- 자원 보호: 장애 발생 시 과부하로 인한 자원 소모 방지
7-2. 기타 활용 사례
- 넷플릭스: 마이크로서비스 아키텍처에서 서비스 간의 안정성을 확보하기 위해 Hystrix를 사용
- 아마존: 대규모 분산 시스템에서 장애 전파를 막고 안정적인 서비스를 제공하기 위해 서킷 브레이커 패턴 적용
- 이베이: 서킷 브레이커를 통해 트래픽 급증 시에도 시스템의 안정성을 유지
8. 결론
서킷 브레이커는 시스템의 안정성과 성능을 향상시키는 데 필수적인 패턴입니다. 특히, 대규모 트래픽이 발생하는 서비스에서는 장애 발생 시 서킷 브레이커를 통해 빠르게 대응하고 시스템을 보호할 수 있습니다.
이번 예제에서는 콘서트 예약 시스템에 서킷 브레이커를 적용하여 성능을 개선하고, 부하 테스트를 통해 그 효과를 검증하였습니다.
서킷 브레이커를 도입함으로써 얻을 수 있는 이점은 다음과 같습니다.
- 장애 전파 방지로 시스템 안정성 확보
- 응답 시간 개선으로 사용자 경험 향상
- 자원 사용 효율화로 서버 비용 절감
앞으로도 서킷 브레이커와 같은 안정성 패턴을 적극적으로 활용하여 더욱 견고한 시스템을 구축해 나가야겠습니다.....
'개발 > Spring' 카테고리의 다른 글
Spring과 Kafka를 활용한 트랜잭셔널 아웃박스 패턴 구현 (0) | 2024.11.21 |
---|---|
MSA 아키텍처로의 전환을 고려한 트랜잭션 처리 및 이벤트 기반 설계 (3) | 2024.11.15 |
Junit & Mock 기반 테스트 코드 도입기 (4) | 2024.09.23 |
Spring 애플리케이션에서 로깅 구현하기 (feat. SLF4J) (0) | 2024.07.12 |
스프링 간단한 커스텀 인증 필터 구현하기 (0) | 2024.06.26 |
깨굴딱지의 코드연못입니다
올챙이가 개구리로 거듭나듯, 끊임없는 노력으로 진화하는 개발자의 길을 걷습니다. 🐸