본문 바로가기
프로젝트

[Project] Circuit Breaker Pattern 에 대해서 알아보자. (1)

by jaee_ 2022. 1. 26.

들어가며

프로젝트 주문 기능을 구현하면서 카카오 지도 API를 사용하는 방법을 택했습니다. 하지만, 만약 API에서 에러가 난다면? 이라는 질문을 만났습니다. 저는 당당하게 Kakao API (이하 외부 API)에 등록되어 있는 에러 코드별로 예외 처리를 할 것 입니다. 라고 답변을 했습니다. 이에 만약 그 API가 외부 응답 코드조차 보낼 수 없는 장애가 발생했다면? 이라는 질문을 다시 듣게 되었고 이는 Circuit Breaker Pattern을 알아보게 되는 계기가 되었습니다. 

주문 시 API 이용 로직

Circuit Breaker Pattern 이 왜 필요할까?

위에서 언급했듯이 외부 API를 사용할 때 응답이 오지 않는 경우 또는 늦어지는 경우가 발생할 수 있습니다. 응답을 받지 못한 요청들은 응답을 받을 때까지 기다리고, 그만큼의 리소스를 차지하기 때문에 이는 메모리 릭으로 이어질 수 있습니다. 그림으로 살펴보겠습니다.

위의 그림처럼 사용자가 요청을 했는데 외부 API 에서 응답이 오지 않으면 핵심 로직을 수행하는 OrderService 는 계속 기다리는 현상이 발생하여 결국 timeout 까지 발생하게 됩니다. 만약 계속 주문 요청이 밀려들어오는 상태라면 계속 쓰레드는 쌓이고, 메모리는 메모리대로 점유하고, 서버에 부하가 걸리고 결국 우리의 서버가 다운될 수도 있습니다. 

 

그리고 저의 경우는 아니지만 Circuit breaker 패턴을 찾아보면서 MSA 아키텍쳐에서 많이 사용된다는 것을 알았습니다. MSA 아키텍쳐란 시스템을 여러 서비스 컴포넌트로 나누고 각 컴포넌트끼리 서로 호출을 하는 패턴을 말합니다. 그림으로 살펴보면 다음과 같은 구조가 됩니다. 

이 경우에도 Service1이 Service2에게 의존하고 있고 Service2가 응답을 보내지 않아 Timeout을 발생시킬 경우 위의 경우와 동일한 문제가 발생할 수 있습니다. 

 

이렇게 하나의 서비스에서 장애가 발생할 경우 그걸 호출하는 서비스까지 기다리는 현상이 발생하고 이는 연쇄적인 장애를 발생시키게 됩니다. 이런 문제를 서비스 간 장애 전파라고 하며 이 문제를 해결하기 위해서 Circuit breaker pattern이 등장하게 되었습니다. 


Circuit Breaker Pattern 는 무엇일까요?

Circuit Breaker를 그대로 직역하면 회로 차단기입니다. 말 그대로 회로 차단기 패턴입니다. 영어를 잘 한다면 패턴 이름만 듣고도 어떤 역할을 하는지 눈치 챌 수 있을 것 같습니다. ㅎㅎ 

 

이는 장애를 감지하고 유지 보수 중 일시적인 외부 시스템 장애 또는 예기치 않은 시스템 장애를 지속적으로 반복하지 않도록 하는 논리를 캡슐화하는 데 사용된다고 위키백과에 적혀져 있습니다. 조금 다르게 설명을 하자면 외부 API (원격 접속)의 성공/실패를 count하여 에러율이 일정 임계치를 넘어섰을 때 자동적으로 접속을 차단하는 시스템을 말합니다. 

 

이해를 돕기 위해 그림으로 살펴보겠습니다. 

Circuit breaker 도입했을 때의 로직

이렇게 OrderService와 이하 외부 API 사이에 회로 차단기 역할을 해주는 Circuit breaker 를 둡니다. 모든 외부 API 로의 호출은 Circuit breaker를 통해서만 이루어지고, 외부 API가 정상적인 상황에선 트래픽이 문제없이 통과합니다. 

 

이는 어떤 원리로 동작할까요? 다음 그림을 보시죠.

  • Close : 초기 상태 입니다. 
  • Open : 에러율이 임계치를 넘어서면 Open 상태가 됩니다. 모든 접속을 fail 처리합니다. 
  • Half_open : Open 으로 설정이 된 후 일정 시간이 지난 후 Half_open 상태가 됩니다. 접속을 시도해서 성공하면 다시 Close 상태로 실패하면 Open 상태로 돌아갑니다. 

 

기본적인 상태는 Close 상태입니다. 장애가 발생하지 않는다면 계속 Close 상태를 유지합니다. 그러다가 장애 발생 시 Open 상태로 변하게 되고. Open 상태일 경우 외부 API 를 호출은 반환되게 됩니다. Open 상태가 되고 일정시간이 지나면 Half_Open 상태로 변경이 되고 혹시 외부 API 가 정상적으로 작동하나~? 하며 확인을 하게 됩니다. 확인한 결과가 정상적으로 작동하면 다시 Close 상태로, 또 실패하면 다시 Open 상태로 변경을 하게 되는 거죠. 

 

Open 상태인 경우엔 외부 API 가 정상적으로 응답할 수 없다는 것을 의미합니다. Circuit breaker 에서 정해진 룰에 따라 임시방편으로 응답을 보낼 메세지를 리턴할 수 있습니다. 이를 Fallback 이라고 칭합니다. 

 

(참고) MSA 아키텍쳐에서 적용한다면 다음과 같은 그림으로 표현할 수 있습니다. 

 


Circuit Breaker Pattern 어떻게 적용시키나요

넷플릭스 구현에서 오픈소스로 Hystrix(Circuit Breaker의 구현 라이브러리)를 제공해줍니다. 

실제로 circuit breaker 적용을 구글링해보면 Hystrix이 많이 나옵니다. 

하지만, Hystrix는 더 이상 개발이 되지 않으며 유지보수를 하는 상태라고 합니다. 기존 Hystrix을 사용하는 프로젝트는 그대로 유지하지만, 새로운 프로젝트는 resilience4j를 사용하며 이를 사용할 것을 권고한다고 합니다. 

 

Resilience4j는 Netflix Hystrix 에서 영감을 받은 가벼운 내결함성 라이브러리 이지만 Java 8 및 함수형 프로그래밍을 위해 설계되었습니다. 라이브러리 는 다른 외부 라이브러리 종속성이 없기 때문에 가볍다고 합니다.

 

다른 방법으로는 envoy,io 프록시 서버를 이용하여 구축할 수도 있습니다. 

 

다음은 resilience4j를 사용하여 적용하는 과정에 대해서 적어보도록 하겠습니다. 


다음 글

[Project] Resilience4j 로 Circuit Breaker 구현하기 (2)


참고한 사이트

https://engineering.linecorp.com/ko/blog/circuit-breakers-for-distributed-services/

https://bcho.tistory.com/1247

https://twowinsh87.github.io/etc/2019/01/19/etc-springboot-circuitbreaker/

댓글