들어가기 전에
어떤 애플리케이션에서 다른 서비스의 API를 호출해 응답 데이터를 사용하는 로직이 있다고 가정해봅시다.
그럼 해당 로직은 아래 프로세스로 동작할 것입니다.
이 두 서비스 간의 통신이 항상 문제없이 정상적으로 동작하면 좋겠지만, 실제로 그렇지 않다는 것을 모두가 알고 있습니다.
- 다른 서비스가 가용 리소스가 적어 이 요청을 처리하는데 과도하게 오랜 시간이 걸린다면?
- 다른 서비스가 현재 장애가 발생해 이 요청을 처리할 수 없는 상태라면?
- 어떤 모종의 이유로 인해 다른 서비스가 내려가 있다면?
이 비즈니스 로직, 나아가 우리의 애플리케이션은 다른 서비스의 상태나 장애에 의존적인 상황이 펼쳐지게 됩니다.
다른 서비스가 장애가 발생하면 우리 서비스도 장애가 발생하는 그런 상황이요.
- 😡 담당자 : 개발자님, 우리 서비스에서 지금 @@@ 기능이 동작하지 않는데 왜 그런 거예요??
- 🥱 개발자 : 아 그거요? A회사에서 제공하는 서비스가 지금 장애가 발생해서 그런 거예요.
- 😡 담당자 : 아니 그래도 우리 서비스가 동작이 되긴 해야죠. 지금 @@@ 기능이 안되니까 나머지도 다 먹통이에요. 빨리 고쳐주세요.
- 😒 개발자 : (나보고 뭘 어쩌라고...)
이런 상황을 막고자 Circuit Breaker 패턴이라는 것이 등장했습니다.
Circuit Breaker Pattern
개요
Circuit Breaker 패턴은 영문 그대로 회로 차단기에서 착안한 디자인 패턴입니다.
회로 차단기는 평소에는 회로를 닫아(CLOSED) 전기가 흐르게 하고, 문제가 발생했을 때 회로를 열어(OPEN) 전기가 흐르게 하지 않는데요.
Circuit Breaker 패턴도 동일합니다.
평소에는 해당 기능을 동작하도록 두다가, 문제가 발생하면 해당 기능 자체를 동작하지 않게 해서 해당 프로세스가 리소스를 점유하지 않도록 해주는 것이죠!
때문에 위 상황에서 다른 서비스에 장애가 발생했을 때, Circuit Breaker 패턴이 해당 기능의 동작을 차단해 해당 비즈니스 로직이 우리 애플리케이션의 리소스를 무한정으로 잡고 있는 상황을 방지해주고, 다른 기능들을 정상적으로 이용할 수 있게 해 줍니다.
한마디로, 다른 서비스에서의 장애가 우리 서비스의 장애로 이어지지 않도록 해준다고 생각하시면 되겠습니다.
상태 값과 상태 간 전환
Circuit Breaker 패턴에는 3가지의 상태가 있습니다.
- CLOSED : 정상 상태
- OPEN : 오류 상태
- HALF_OPEN : 오류 상태에서 정상 상태 여부를 판단하기 위한 반 열림 상태
이 상태 값들은 아래 과정으로 결정됩니다.
- 다른 서비스로의 요청 발생
- 요청이 정상적으로 수행되면 상태를 CLOSED로 세팅
- 이후 요청이 실패 시 상태를 OPEN으로 세팅
- 로직에서 해당 요청이 필요한 경우 상태가 OPEN 상태이면 스킵
- 설정된 시간이 지나면 상태를 OPEN에서 HALF_OPEN으로 변경
- 상태가 HALF_OPEN일 때, 설정된 개수만큼의 요청 허용
- 이후 요청이 성공했을 경우 상태를 CLOSED로 변경
Circuit Breaker Pattern의 구현체
Spring에서 Circuit Breaker 패턴을 구현한 라이브러리는 대표적으로 Netflix Hystrix와 Resilience4j가 있으며, 각각 Spring Cloud Starter 의존성으로도 제공이 되었습니다.
- Netflix Hystrix : spring-cloud-starter-netflix-hystrix
- Resilience4j : spring-cloud-starter-circuitbreaker-resilience4j
이번 포스팅에서는 Resilience4j를 중점적으로 알아보고, 간단히 Netflix Hystrix와 비교해보겠습니다.
Resilience4j 란?
Resilience4j는 Netflix Hystrix와 같은 fault tolerance 라이브러리입니다.
Hystrix와 달리 다른 라이브러리에 의존성도 없어(Vavr 제외) 가볍고, Netflix Hystrix의 OSS Lifecycle이 maintenance이기 때문에 최신 버전(2.4.5)의 Spring Boot에서도 Resilience4j(Spring Cloud Circuit Breaker)를 제공합니다.
그리고 Resilience4j는 함수형 프로그래밍과 람다, 메서드 참조를 지원합니다.
Resilience4j에는 6개의 Core Module이 있는데, 아래와 같습니다.
- Circuit Breaker
- Bulkhead
- RateLimiter
- Retry
- TimeLimiter
- Cache
Circuit Breaker 모듈
- Circuit Breaker 패턴을 구현한 모듈
- 요청 중 지연된 응답이 몇 퍼센트 이상일 때 서킷의 상태를 CLOSED에서 OPEN으로 바꿀지 설정
- 서킷 상태가 OPEN일 때 CallNotPermittedException과 함께 요청 거절
- 서킷 상태가 OPEN이 되면 설정한 시간 이후에 HALF_OPEN으로 바뀌고 설정한 수만큼 요청을 허용해 서버가 사용 가능 상태인지 확인
- 서킷 상태를 바꾸는 방식(sliding window)에는 Count-based sliding window, Time-based sliding window 두 가지가 있음
Count-based sliding window
N번의 요청 중 M번 실패했을 때 실패율(Failure Rate)이 설정값(failureRateThreshold) 보다 클 경우 서킷 상태를 OPEN으로 변경시키는 방식
Time-based sliding window
N번의 요청 중 요청 시간이 M시간을 초과하는 퍼센트(Slow Call Rate)가 설정값(slowCallRateThreshold) 보다 클 경우 서킷 상태를 OPEN으로 변경시키는 방식
Bulkhead 모듈
- 동시 실행 수를 제한
- Semaphore 방식 -> SemaphoreBulkhead
- 고정된 Thread pool과 Bounded queue를 사용하는 FixedThreadPoolBulkHead
RateLimiter 모듈
- 일정 시간 동안 요청 수를 제한
Retry 모듈
- 요청이 실패했을 경우 재시도 정책
TimeLimiter 모듈
- 원격 서버를 호출하는데 걸리는 시간제한
Spring Cloud Circuit Breaker
최근까지 Spring Cloud는 Spring Cloud Netflix Hystrix로만 Circuit Breaker를 제공했습니다. 그러나 Spring Cloud Netflix 프로젝트가 어노테이션 기반이면서 두 라이브러리(Spring Cloud Netflix - Netflix Hystrix) 간 강한 결합이 있었고, 애플리케이션 코드의 변경 없이 Circuit Breaker 구현체를 변경할 수 없었습니다.
그래서 Spring Cloud Circuit Breaker는 추상 레이어를 제공해 다른 Circuit Breaker의 구현을 제공합니다.
Spring Cloud Circuit Breaker는 Resilience4j 뿐만 아니라 다른 구현체도 지원을 하는데, Spring Cloud Circuit Breaker는 추상 레이어를 제공하기 때문에 다른 구현체로의 전환뿐만 아니라, 여러 구현체를 섞어서 사용할 수도 있습니다.
References
'🌱 SPRING' 카테고리의 다른 글
[Spring Cloud Config] 설정값을 외부에서 관리하자! - 실습 (4) | 2021.10.10 |
---|---|
[Spring Cloud Config] 설정값을 외부에서 관리하자! - 기본 (0) | 2021.10.10 |
[SpringBoot] 컨트롤러, View(JSP) 작성하기 (0) | 2020.05.30 |
[SpringBoot] 스프링 부트 프로젝트 생성 (0) | 2020.05.30 |
@MVC : RequestMapping (0) | 2018.03.29 |