에듀테크 프로젝트 대시보드
서킷 브레이커 (Circuit Breaker)
분산 시스템에서 한 서비스가 죽으면, 그 서비스를 호출하던 다른 서비스들의 스레드가 응답을 기다리며 줄줄이 멈춘다. 이 연쇄 장애(cascading failure)를 막는 장치가 전기 회로의 두꺼비집(차단기)에서 이름을 딴 서킷 브레이커다. 실패가 임계값을 넘으면 회로를 열어(OPEN) 호출을 즉시 실패시키고, 잠시 뒤 반열림(HALF_OPEN) 상태로 슬쩍 찔러보며 회복을 확인한다.
빠른 실패 = 브레이커가 아픈 서비스를 아예 호출하지 않고 즉시 되돌린 요청. 그만큼 스레드·타임아웃 자원을 아낀 것이다.
평소 상태. 모든 요청을 서비스로 그대로 전달한다. 실패가 발생할 때마다 카운터를 올리고, 성공하면 0으로 리셋. 연속 실패가 임계값에 도달하면 → 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
배의 격벽처럼, 한 칸에 물이 차도 배 전체가 가라앉지 않게 하는 것 — 그게 서킷 브레이커·벌크헤드·타임아웃으로 이루는 회복 탄력성(resilience)이다.