서킷 브레이커에 대해 얘기를 나누다가 '쿠버네티스가 Health Check로 파드(Pod)를 알아서 격리하고 재시작해주는데, 굳이 서킷 브레이커(Circuit Breaker)를 별도로 구축해야 할까?' 라는 의문이 들었다.
결론적으로, 두 기술은 목적과 역할이 달라 서로를 대체할 수 없으며 함께 사용될 때 비로소 진정한 안정성을 확보할 수 있는 상호 보완적인 관계다. 이 글에서는 두 기술의 역할을 명확히 구분하고 함께 사용했을 때의 이점에 대해 다루고자 한다.
먼저 쿠버네티스가 제공하는 기본적인 헬스 체크 기능인 프로브(Probe)에 대해 알아보자.
이 프로브들은 컨테이너의 상태를 HTTP GET 요청, TCP 소켓 연결, 내부 명령어 실행(exec) 이라는 세 가지 기준으로 판단하며 initialDelaySeconds, periodSeconds, failureThreshold 등의 설정값으로 동작을 세밀하게 제어할 수 있다. 또한 Liveness와 Readiness 프로브는 서로 독립적이고 병렬로 동작한다.
서킷 브레이커는 특정 서비스로의 요청이 계속 실패하면 말 그대로 회로를 끊어버려 추가적인 요청 시도를 막는 패턴이다.
서킷 브레이커는 세 가지 상태를 갖는다.
두 기술의 차이를 이해하기 위해, 주문 서비스가 결제 서비스를 호출하는 상황에서 결제 서비스의 DB에 장애가 발생한 경우를 가정해보자.
기본적인 Readiness Probe는 웹 서버의 응답 여부만 확인하므로, 결제 서비스의 파드 자체는 정상 구동 중으로 판단한다. 따라서 쿠버네티스는 결제 서비스가 건강하다고 보고, 주문 서비스의 요청을 계속해서 전달한다.
하지만 결제 서비스는 DB 장애로 인해 모든 요청을 처리하지 못하고 타임아웃이나 500 에러를 반환한다. 이로 인해 주문 서비스는 응답 없는 요청을 계속 대기하게 되어 가용 스레드를 모두 소진하게 되고 이는 연쇄 장애(Cascading Failure)로 이어질 수 있다.
주문 서비스에 구현된 서킷 브레이커는 결제 서비스로의 요청 실패율 급증을 즉시 감지하고, 회로를 Open 상태로 전환한다.
이후 주문 서비스는 더 이상 결제 서비스로 네트워크 요청을 보내지 않고, 즉시 에러를 반환하거나 미리 정의된 대체 로직(Fallback)을 수행한다. 이를 통해 불필요한 자원 낭비를 막고 장애의 연쇄적인 전파를 차단하여 시스템 전체를 보호한다.
그렇다면 Readiness Probe에서 외부 DB 연결까지 확인하도록 설정하면 되지 않을까? 그러나 이는 회복 과정에서 서킷 브레이커와 결정적인 차이가 발생한다.
Readiness Probe의 경우 DB가 복구되는 순간, 모든 파드가 거의 동시에 Readiness Probe에 성공한다. 그 결과, 쿠버네티스는 대기 중이던 모든 클라이언트의 요청 트래픽을 갓 회복된 서비스로 한꺼번에 쏟아붓게 된다. 이로 인해 서비스는 다시 장애 상태에 빠질 수 있는데 이를 Thundering Herd 문제라고 한다.
반면, 서킷 브레이커는 Half-Open 상태가 존재한다. 즉 회로가 열린 후 소수의 테스트 요청만으로 서비스의 실제 복구 여부를 확인하고 이후 회로를 닫아 전체 트래픽을 정상화시키므로 시스템에 주는 부담이 적다.
구분 | Kubernetes Probes (Liveness/Readiness) | Circuit Breaker |
---|---|---|
관점 | 서버(호출받는 쪽)의 관점 | 클라이언트(호출하는 쪽)의 관점 |
보호 대상 | 개별 파드 자신 | 클라이언트 애플리케이션과 전체 시스템 |
판단 기준 | 파드 내부의 상태 (프로세스, 포트, 스크립트 실행) | 외부 서비스의 응답 상태 (성공/실패율, 지연 시간) |
핵심 기능 | 파드 재시작 또는 트래픽 격리 | 즉시 실패(Fail-Fast) 및 장애 전파 방지, 점진적 회복 |
쿠버네티스의 Liveness/Readiness Probe는 개별 파드의 상태를 관리하는 인프라 레벨의 기능이다.
반면, 서킷 브레이커는 서비스 간의 의존성 관계에서 장애 전파를 방지하는 애플리케이션 레벨의 디자인 패턴이다.
따라서 두 기술은 선택의 문제가 아니다. 기본적인 안정성은 Health Check으로 확보하고 서비스 간 의존성이 높은 환경에서는 서킷 브레이커를 함께 구축하여 더욱 견고하고 회복탄력성 있는 아키텍처를 지향해야 한다.