한양과학기술고등학교

에듀테크 프로젝트 대시보드

서킷 브레이커 (Circuit Breaker)

서킷 브레이커 (Circuit Breaker)

분산 시스템에서 한 서비스가 죽으면, 그 서비스를 호출하던 다른 서비스들의 스레드가 응답을 기다리며 줄줄이 멈춘다. 이 연쇄 장애(cascading failure)를 막는 장치가 전기 회로의 두꺼비집(차단기)에서 이름을 딴 서킷 브레이커다. 실패가 임계값을 넘으면 회로를 열어(OPEN) 호출을 즉시 실패시키고, 잠시 뒤 반열림(HALF_OPEN) 상태로 슬쩍 찔러보며 회복을 확인한다.

인터랙티브 데모

State Machine

CLOSED정상 통과
→
OPEN빠른 실패
→
HALF_OPEN회복 확인
Client요청 발생
──
BreakerCLOSED
──
Service건강함

Breaker 내부 상태

stateCLOSED
연속 실패 수0
OPEN 해제까지—
HALF_OPEN 성공 프로브—

누적 통계

0
요청
0
성공
0
서비스 오류
0
빠른 실패(차단)

빠른 실패 = 브레이커가 아픈 서비스를 아예 호출하지 않고 즉시 되돌린 요청. 그만큼 스레드·타임아웃 자원을 아낀 것이다.

서비스 상태 (수동 조작)

브레이커 설정

요청 로그

세 가지 상태

CLOSED · 닫힘

평소 상태. 모든 요청을 서비스로 그대로 전달한다. 실패가 발생할 때마다 카운터를 올리고, 성공하면 0으로 리셋. 연속 실패가 임계값에 도달하면 → OPEN.

OPEN · 열림

회로 차단. 서비스를 호출하지 않고 즉시 예외를 던진다(빠른 실패). 호출 측 스레드가 타임아웃까지 붙잡히지 않는다. 설정한 유지 시간이 지나면 → HALF_OPEN.

HALF_OPEN · 반열림

탐색 상태. 소수의 요청만 통과시켜 서비스가 살아났는지 확인한다. 프로브가 연속 N회 성공하면 → CLOSED, 한 번이라도 실패하면 곧바로 → OPEN.

핵심 구현 (의사 코드)

# 상태: CLOSED / OPEN / HALF_OPEN
class CircuitBreaker:
    def call(self, fn):
        if self.state == "OPEN":
            if now() - self.opened_at < self.timeout:
                raise CircuitOpenError()      # 빠른 실패, fn 호출 안 함
            self.state = "HALF_OPEN"              # 찔러볼 시간
            self.probe_ok = 0

        try:
            result = fn()                        # 실제 원격 호출
        except Exception:
            self.fails += 1
            if self.state == "HALF_OPEN" or self.fails >= self.threshold:
                self.state, self.opened_at = "OPEN", now()
            raise

        # 성공 처리
        if self.state == "HALF_OPEN":
            self.probe_ok += 1
            if self.probe_ok >= self.need_probes:
                self.state = "CLOSED"
        self.fails = 0
        return result

현실에서는

  • 슬라이딩 윈도우: 단순 연속 실패가 아니라 "최근 100건 중 실패율 50% 이상"처럼 비율 기반으로 판단하는 구현이 많다(Resilience4j, Envoy).
  • 타임아웃과 짝: 브레이커만으로는 부족하다. 느린 응답을 실패로 세려면 각 호출에 타임아웃이 걸려 있어야 한다.
  • 폴백(fallback): OPEN일 때 그냥 에러를 내는 대신 캐시된 값, 기본값, "잠시 후 다시 시도" 화면을 돌려주면 사용자 경험이 유지된다.
  • 지터(jitter): HALF_OPEN 복귀 시각을 인스턴스마다 살짝 흩어 놓아야 수백 대가 동시에 죽은 서비스로 몰려가는 thundering herd를 피한다.
  • 벌크헤드(bulkhead)와 함께 쓴다: 서비스별로 스레드풀·커넥션풀을 격리해 한 곳의 장애가 전체 자원을 삼키지 못하게 한다.

배의 격벽처럼, 한 칸에 물이 차도 배 전체가 가라앉지 않게 하는 것 — 그게 서킷 브레이커·벌크헤드·타임아웃으로 이루는 회복 탄력성(resilience)이다.