Health Check가 서킷 브레이커를 대체할 수 있을까?

jione ·2025년 7월 19일
1

서킷 브레이커에 대해 얘기를 나누다가 '쿠버네티스가 Health Check로 파드(Pod)를 알아서 격리하고 재시작해주는데, 굳이 서킷 브레이커(Circuit Breaker)를 별도로 구축해야 할까?' 라는 의문이 들었다.

결론적으로, 두 기술은 목적과 역할이 달라 서로를 대체할 수 없으며 함께 사용될 때 비로소 진정한 안정성을 확보할 수 있는 상호 보완적인 관계다. 이 글에서는 두 기술의 역할을 명확히 구분하고 함께 사용했을 때의 이점에 대해 다루고자 한다.

Liveness & Readiness Probes

먼저 쿠버네티스가 제공하는 기본적인 헬스 체크 기능인 프로브(Probe)에 대해 알아보자.

Liveness Probe

  • 목적: 컨테이너가 살아있는지 확인
  • 실패 시: 컨테이너 재시작
  • 교착 상태(Deadlock)에 빠져 애플리케이션이 멈췄지만, 프로세스는 종료되지 않은 경우 감지하여 자동 복구할 때 사용

Readiness Probe

  • 목적: 컨테이너가 요청을 처리할 준비가 되었는지 확인
  • 실패 시: 서비스의 로드 밸런서 대상에서 제외하여 새로운 트래픽을 보내지 않음
  • 애플리케이션 시작 시 대용량 데이터를 로딩하거나, 외부 서비스와 연결하는 등 내부적으로 준비 과정이 필요할 때 사용

이 프로브들은 컨테이너의 상태를 HTTP GET 요청, TCP 소켓 연결, 내부 명령어 실행(exec) 이라는 세 가지 기준으로 판단하며 initialDelaySeconds, periodSeconds, failureThreshold 등의 설정값으로 동작을 세밀하게 제어할 수 있다. 또한 Liveness와 Readiness 프로브는 서로 독립적이고 병렬로 동작한다.


Circuit Breaker

서킷 브레이커는 특정 서비스로의 요청이 계속 실패하면 말 그대로 회로를 끊어버려 추가적인 요청 시도를 막는 패턴이다.

서킷 브레이커는 세 가지 상태를 갖는다.

Closed

  • 정상 상태
  • 모든 요청이 정상적으로 전달

Open

  • 장애 상태
  • 요청 실패율이 임계치를 넘으면 회로가 열림
  • 이후 들어오는 요청은 실제 서비스로 전달되지 않고 즉시 실패 처리(Fail-Fast)
  • 이를 통해 클라이언트의 자원 낭비를 막고 장애 전파 방지

Half-Open

  • 복구 확인 상태
  • 회로가 열린 후 일정 시간이 지나면, 소수의 테스트용 요청을 보내 서비스가 복구되었는지 확인하고 성공 시 회로 Close, 실패 시 다시 Open

Health Check vs. Circuit Breaker

두 기술의 차이를 이해하기 위해, 주문 서비스가 결제 서비스를 호출하는 상황에서 결제 서비스의 DB에 장애가 발생한 경우를 가정해보자.

Health Check의 관점

기본적인 Readiness Probe는 웹 서버의 응답 여부만 확인하므로, 결제 서비스의 파드 자체는 정상 구동 중으로 판단한다. 따라서 쿠버네티스는 결제 서비스가 건강하다고 보고, 주문 서비스의 요청을 계속해서 전달한다.

하지만 결제 서비스는 DB 장애로 인해 모든 요청을 처리하지 못하고 타임아웃이나 500 에러를 반환한다. 이로 인해 주문 서비스는 응답 없는 요청을 계속 대기하게 되어 가용 스레드를 모두 소진하게 되고 이는 연쇄 장애(Cascading Failure)로 이어질 수 있다.

Circuit Breaker의 관점

주문 서비스에 구현된 서킷 브레이커는 결제 서비스로의 요청 실패율 급증을 즉시 감지하고, 회로를 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으로 확보하고 서비스 간 의존성이 높은 환경에서는 서킷 브레이커를 함께 구축하여 더욱 견고하고 회복탄력성 있는 아키텍처를 지향해야 한다.

0개의 댓글