Architecture/MSA

[TIL] 서킷 브레이커의 상태 변화(Closed -> Open -> Half-Open)와 주의할 점

쉬지마 이굥진 2024. 8. 7. 02:51

오늘은 마이크로서비스 아키텍쳐를 학습하면서 알게된 서킷브레이커의 상태 변화에 대해 자세히 포스팅해보려고 한다. 상태가 어떤 상황에서 어떻게 변하는지, 각 상태는 어떤 상황을 말하는지 등을 알아가보자.

(사실 깊게 포스팅하려면 MSA의 구조와 환경, 장애전파 가능성 및 장애격리, ...등등에 대해서까지 명시하면 좋지만 이 포스팅에서는 그 부분은 간단히 쓰고 서킷 브레이커에 초점을 맞춰서 쓰도록 하겠다)

 

<참고하면 좋을 글>

 

[프로젝트] 모놀리식과 MSA: MSA 구조 채택 이유

들어가며이번 프로젝트에서 모놀리식 아키텍쳐 대신 MSA 구조를 선택하기로 하면서, 모놀리식 아키텍쳐와 MSA는 어떻게 다르고 왜 이런 의사결정을 하기로 했는지 현재 프로젝트에 빗대어 기술

developer-jinnie.tistory.com

 

 

0. 서킷 브레이커(circuit breaker)의 등장 배경

MSA와 같은 분산 환경에서는 서비스가 다른 서비스를 동기 호출 시 실패할 가능성이 항상 존재한다. 서비스가 모두 개별 프로세스로 동작하고 있기 때문에 응답하지 못하거나, 응답이 매우 늦어지는 문제가 발생할 수 있다.

또한, 클라이언트의 요청이 수개의 서비스를 거쳐 응답이 이뤄질수도 있다. 서비스 B로부터 시작된 장애가 서비스 A, C, D, E, ... 까지 영향을 미칠 수 있다는 의미이다. 즉, 하나의 서비스의 장애가 연쇄적으로 이어져 전체 서비스의 장애로까지 이어질 수 있다.

 

더 큰 문제는, 이런 상황에서 장애의 시작점을 파악하는 것이 쉽지 않다는 것이다. 그렇기 때문에 마이크로 서비스 아키텍처는 스스로 회복해야하며, 장애를 격리할 수 있어야 한다.

 

위 문제를 해결하기 위해 등장한 것이 서킷 브레이커 패턴이다. 서킷 브레이커 패턴은 이름과 같이 전기회로의 퓨즈와 유사한 개념으로, 장애가 발생한 서비스에 대한 호출을 중단하고 빠르게 실패를 반환함으로써 전체 시스템의 안정성을 유지하는 역할을 한다.

 

1. 서킷 브레이커란?

다시 말하면, 서킷 브레이커는 소프트웨어 시스템에서 장애나 성능 저하가 발생했을 때, 전체 시스템의 안정성을 유지하기 위해 특정 기능/서비스를 일시적으로 차단(장애 격리)하는 패턴이다. 이 패턴은 시스템의 복원력과 안정성을 높이기 위해 사용되는데, 주로 마이크로서비스 아키텍처나 분산 시스템에서 서비스 간의 의존성을 관리할 때 많이 사용된다.

다양한 서킷 브레이커 기능을 제공하는 서킷 브레이커 라이브러리로는 Resilience4j 등이 있다.

 

서킷 브레이커의 상태는 클로즈드 → 오픈 하프-오픈 이렇게 3단계로 변화된다. 상태에 대해 자세히 보기 전에, 클로즈드 오픈 하프오픈 이런 식으로 계층적으로 변화하는 것이 아니라 상황에 따라 왔다리 갔다리(?) 한다는 걸 미리 알아가자.

 

 

2. 서킷 브레이커의 상태 변화

상태 변화 도식

 

서킷 브레이커는 Closed, Open, Half-Open 상태를 통해 호출 실패를 관리한다.

 

2-1. Closed (기본 상태)

  • 기본 상태로, 모든 요청을 통과시키는 상태이다.
  • 이 상태에서 호출이 실패하면 실패 카운터가 증가한다.
  • 실패율이 설정된 임계값을 초과하면 서킷 브레이커가 오픈 상태로 전환된다.
  • ex) 임계값이 50%일 때, 최근 5번의 호출 중 3번이 실패해서 실패율이 60%에 도달하면 오픈 상태로 전환된다.

2-2. Open

  • 서킷 브레이커가 오픈 상태로 전환되면 모든 요청을 즉시 실패로 처리한다.
  • 👉 특정 기능이나 서비스에 문제가 발생했을 때, 더 이상의 요청을 막아 시스템의 나머지 부분이 영향을 받지 않도록 하는 것이다.
  • 대기 시간을 설정한다. 설정된 대기 시간이 지나면 서킷 브레이커는 하프-오픈 상태로 전환된다.
  • ex) 대기 시간을 20초로 설정하면, 서킷 브레이커가 오픈 상태로 전환되고 20초 동안 모든 요청이 차단된다. 20초가 지나면 하프-오픈 상태로 전환된다.

2-3. Half-Open

  • 오픈 상태에서 대기 시간이 지나면 서킷 브레이커는 하프-오픈 상태로 전환된다.
  • 하프-오픈 상태에서는 제한된 수의 요청을 허용하여 시스템이 정상 상태로 복구되었는지 확인한다.
    • 요청이 성공하면 서킷 브레이커는 클로즈드 상태로 전환된다.
    • 요청이 다시 실패하면 서킷 브레이커는 다시 오픈 상태로 전환된다.
  • ex) 하프-오픈 상태에서 3개의 요청을 허용하고, 모두 성공하면 클로즈드 상태로 전환된다. 만약 하나라도 실패하면 다시 오픈 상태로 전환된다.

 

3. 주의할 점 - Fallback 처리⭐

서킷 브레이커, Resilience4j의 특징 중 하나가 Fallback이다. Fallback은 외부 서비스 호출이 실패했을 때 대체 로직을 제공하는 일종의 메서드이다. 말로만 하면 어려울 수 있으니 예시를 들어보자.

ex) 우리가 설계한 로직은 'A'라는 로직을 타야한다. 하지만 만약 A 로직에 에러가 생겼을 때, 이를 대체할 '_A' 로직을 만들어서 A 로직 fail 시에는 _A 로직을 대신 탈 수 있도록 fallback 로직을 만들어 설계하는 것이다.

 

시스템의 안정성을 높이고, 장애가 발생해도 사용자에게 일정한 응답을 제공할 수 있으며, 장애가 다른 서비스에 전파되는 것을 방지한다는 장점이 있다. 

프로메테우스와 같은 도구들을 통해서 서킷 브레이커 상태를 모니터링하고 로그를 확인하며 관리할 수 있는 다양한 도구를 제공하기도 한다.

 

서킷 브레이커에 대한 더 자세한 내용들은 공식문서에 가면 확인할 수 있으니, 더 많은 정보를 원하다면 공식문서에서 확인해 보자.

 

[예시 코드]

@Service
public class MyService {

    // fallbackMethod에 원하는 메서드의 이름을 써두면, 문제가 생겼을 때 이 이름의 메서드를 호출
    @CircuitBreaker(name = "myService", fallbackMethod = "fallbackMethod")
    // 이 코드에 문제가 생겼을 시, 이 코드는 타지 않음
    public String myMethod() {
        // ...
        return externalService.call();
    }

    // 다이렉트로 이 메서드를 탐
    public String fallbackMethod(Throwable t) {
    	// alert, slack 등 다양한 알림 로직이 올 수 있음 (장애 발생을 알리기 위해)
        return "Fallback response";
    }
}

 

 

4. 마치며

오늘은 MSA 환경에서의 서킷 브레이커와 그 상태 변화, Fallback 매커니즘에 대해서 학습해봤다.

각 상태가 어떤 상황에서 어떤 역할을 하는지 이해함으로써 앞으로의 MSA 시스템 설계에 큰 도움이 될 것 같고!  (특히, Fallback 로직을 통해 장애 발생 시에도 일정한 응답을 제공하고, 시스템의 지속성을 유지할 수 있다는 점이 흥미로웠다) 앞으로 있을 MSA 프로젝트에서도 서킷 브레이커 패턴을 활용해서 MSA 환경에서도 안정적이고 탄력적인 시스템까지 구축해보는 걸 목표로 더 깊게 학습해봐야겠다.

 

다음 포스팅은 실제 프로젝트에서의 Resilience4j 설정 방법에 대해서 들고오겠다 :-) 땡큐포와칭


References

https://martinfowler.com/bliki/CircuitBreaker.html

https://mangkyu.tistory.com/289

https://hudi.blog/circuit-breaker-pattern/

https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/#spring-cloud-feign-circuitbreaker