핵심 인사이트 (3줄 요약)
- 본질: 서킷 브레이커 (Circuit Breaker) 패턴은 최근 실패율과 지연을 관찰해, 문제가 있는 외부 의존성 호출을 잠시 차단하고 빠르게 실패시키는 회복탄력성 (Resilience) 제어 장치다.
- 가치: 타임아웃 대기와 스레드 고갈을 줄여 연쇄 장애 (Cascading Failure)를 막고, 장애 중에도 대체 응답이나 우아한 성능 저하를 가능하게 한다.
- 판단 포인트: 진짜 핵심은 패턴 이름이 아니라 실패로 볼 예외의 범위, 임계치, 반개방 상태의 탐침 수, 안전한 폴백 (Fallback) 설계가 적절한가에 있다.
Ⅰ. 개요 및 필요성
분산 시스템에서 가장 위험한 장애는 "하나가 죽었는데 모두가 같이 느려지는" 상황이다. 주문 서비스가 결제 서비스를 동기 호출하고, 결제 서비스가 카드사 애플리케이션 프로그래밍 인터페이스 (API, Application Programming Interface) 에 묶여 있다면, 카드사 응답 지연이 주문 스레드를 붙잡고 결국 전체 시스템 처리량을 떨어뜨릴 수 있다.
문제는 실패 자체보다 기다림의 전염성이다. 의존 서비스가 5초씩 응답을 지연시키면, 호출자는 그동안 연결과 스레드를 점유한다. 여기에 재시도까지 겹치면 부하가 더 커지고, 결국 처음에는 외부 한 지점의 문제였던 것이 애플리케이션 서버, 데이터베이스 연결 풀, 게이트웨이까지 확산된다.
서킷 브레이커는 이 악순환을 끊기 위해 등장했다. 전기 차단기처럼 이상 징후가 반복되면 회로를 잠시 열어 두고, 그동안은 "호출해도 소용없는 곳"으로 요청을 보내지 않는다. 즉, 실패를 숨기는 패턴이 아니라 실패를 빨리 인정해 전체를 보호하는 패턴이다.
아래 흐름은 연쇄 장애가 어떻게 커지는지를 보여 준다.
┌──────────────────────────────────────────────────────────────────────┐
│ Slow dependency can poison healthy callers │
├──────────────────────────────────────────────────────────────────────┤
│ User Request -> Order Service -> Payment Service -> External API │
│ │ │ │
│ │ └─ slow / timeout │
│ │ │
│ └─ waiting threads accumulate │
│ │ │
│ ▼ │
│ queue growth -> pool exhaustion│
└──────────────────────────────────────────────────────────────────────┘
서킷 브레이커는 이 경로에서 "외부 API가 이미 아픈데 왜 계속 문을 두드리느냐"를 묻는 장치다. 장애를 없애지는 못하지만, 장애 범위를 국소화해 시스템 전체 붕괴를 막는다.
- 📢 섹션 요약 비유: 아파트 한 집에서 합선이 났을 때 바로 차단기를 내려야 다른 집 전기까지 나가지 않듯, 서킷 브레이커는 한 서비스의 고장을 전체 정전으로 키우지 않게 막는 장치다.
Ⅱ. 아키텍처 및 핵심 원리
서킷 브레이커의 핵심은 상태 기계와 관찰 지표다. 일반적으로 닫힘 (Closed), 열림 (Open), 반개방 (Half-Open) 세 상태를 돌며 최근 호출의 실패율, 느린 호출 비율, 최소 호출 수, 대기 시간을 기준으로 상태를 바꾼다.
| 상태 | 의미 | 동작 |
|---|---|---|
| Closed | 정상 감시 상태 | 요청을 통과시키며 실패율·지연을 계속 측정 |
| Open | 차단 상태 | 의존 서비스로 보내지 않고 즉시 실패 또는 폴백 반환 |
| Half-Open | 회복 시험 상태 | 제한된 수의 탐침 요청만 허용해 복구 여부 판단 |
아래 상태 전이는 대부분의 구현이 공유하는 기본 골격이다.
┌──────────────────────────────────────────────────────────────────────┐
│ Circuit Breaker state machine │
├──────────────────────────────────────────────────────────────────────┤
│ failure rate / slow calls > threshold │
│ CLOSED -------------------------------------------> OPEN │
│ │ │ │
│ │ success traffic │ wait time │
│ │ ▼ │
│ └<----------------------- HALF-OPEN <--------------┘ │
│ enough probe success any probe failure │
└──────────────────────────────────────────────────────────────────────┘
여기서 중요한 것은 "무엇을 실패로 세느냐"다. 일반적으로 연결 실패, 타임아웃, 5xx 응답, 과도한 지연은 실패로 집계하지만, 잘못된 사용자 입력으로 인한 4xx 응답까지 실패로 포함하면 브레이커가 왜곡된다. 즉 서킷 브레이커는 비즈니스 예외보다 의존성 건강 상태를 감시해야 한다.
또한 최근 구현체는 단순 실패율만 보지 않고 느린 호출 비율도 함께 본다. 아직 완전히 죽지 않았더라도 응답 시간이 서비스 수준 목표 (SLO, Service Level Objective)를 무너뜨릴 만큼 느려졌다면, 미리 차단해 자원 고갈을 막는 편이 더 안전하기 때문이다.
서킷 브레이커는 코드 라이브러리 안에 둘 수도 있고, 서비스 메시 (Service Mesh) 나 API 게이트웨이 계층에 둘 수도 있다. 라이브러리 방식은 호출 맥락에 맞는 세밀한 제어가 쉽고, 프록시 방식은 정책 일관성이 좋다.
- 📢 섹션 요약 비유: 서킷 브레이커는 가게 문을 영원히 닫는 자물쇠가 아니라, 손님이 몰려도 주방이 불날 조짐이 보이면 잠시 입장을 멈추고 주방 상태를 확인하는 안전 관리자와 같다.
Ⅲ. 비교 및 연결
서킷 브레이커를 제대로 쓰려면 비슷해 보이는 다른 회복탄력성 패턴과 역할을 구분해야 한다. 실패를 늦추는 기술과 실패를 빨리 인정하는 기술은 목적이 다르다.
| 패턴 | 답하는 질문 | 잘하는 일 | 주의점 |
|---|---|---|---|
| 타임아웃 (Timeout) | 얼마나 오래 기다릴 것인가 | 무한 대기 방지 | 너무 길면 자원 고갈, 너무 짧으면 오탐 |
| 재시도 (Retry) | 잠깐 흔들린 실패를 다시 해볼까 | 일시적 오류 복구 | 과하면 장애를 증폭 |
| 서킷 브레이커 | 반복 실패 중 계속 호출할까 | 연쇄 장애 차단 | 임계치 조정 실패 시 과차단 가능 |
| 벌크헤드 (Bulkhead) | 자원을 구획할까 | 장애 격리 | 풀 크기 설계 필요 |
| 폴백 (Fallback) | 실패 시 무엇을 보여 줄까 | 사용자 경험 완화 | 거짓 성공을 만들면 위험 |
실무에서는 이들을 조합해서 쓴다. 먼저 짧고 명확한 타임아웃을 걸고, 멱등성 (Idempotency) 이 보장되는 경우에만 제한된 재시도를 허용하며, 그래도 실패가 누적되면 서킷 브레이커가 회로를 연다. 동시에 벌크헤드로 스레드나 커넥션 풀을 분리하면 장애 확산을 더 줄일 수 있다.
이 조합에서 가장 위험한 것은 "재시도가 항상 좋은 일"이라는 오해다. 이미 의존성이 과부하 상태라면 재시도는 치료제가 아니라 부하 증폭기다. 그래서 서킷 브레이커는 재시도와 경쟁하는 패턴이 아니라, 재시도가 더 이상 이롭지 않은 순간을 선언하는 패턴으로 이해해야 한다.
- 📢 섹션 요약 비유: 타임아웃은 기다릴 시간표, 재시도는 다시 문 두드리기, 벌크헤드는 방화문, 서킷 브레이커는 "이제 문 두드리는 걸 멈춰"라고 판단하는 안전 요원과 같다.
Ⅳ. 실무 적용 및 기술사 판단
대표적인 적용 지점은 결제, 재고, 추천, 외부 인증처럼 실패가 잦거나 응답 시간이 흔들리는 네트워크 경계다. 예를 들어 상품 조회는 캐시 폴백이 가능하지만, 결제 승인 API는 "일단 성공으로 간주" 같은 폴백이 절대 허용되지 않는다. 따라서 브레이커 설정은 의존성별로 분리해야 한다.
기술사 판단 체크리스트
- 브레이커를 서비스 전체가 아니라 의존성·엔드포인트 단위로 나누었는가?
- 실패율 계산에서 4xx 같은 비즈니스 오류를 제외했는가?
- 타임아웃과 재시도 정책이 브레이커보다 앞단에서 정리되어 있는가?
- Half-Open 상태에서 허용할 탐침 요청 수가 충분히 작고 안전한가?
- 폴백이 사용자 경험은 지키되 데이터 정합성을 해치지 않는가?
채택 / 회피 판단
- 채택: 외부 API, 원격 서비스, 캐시·메시지 브로커처럼 네트워크·지연 불확실성이 큰 의존성
- 회피 또는 별도 설계: 입력 검증 오류, 로컬 함수 호출, 실패를 숨기면 안 되는 금융 승인 결과 왜곡 시나리오
자주 나오는 안티패턴
- 여러 의존성을 하나의 공용 브레이커로 묶는 경우
- 에러율만 보고 느린 호출 비율은 측정하지 않는 경우
- 공격적으로 재시도한 뒤 다시 브레이커까지 열어 부하를 폭증시키는 경우
- 폴백으로 빈 데이터나 가짜 성공을 반환해 장애를 숨기는 경우
- 메트릭과 알림 없이 브레이커를 켜 두고 실제 개방 상태를 모르는 경우
실무에서는 임계치를 보수적으로 시작해 트래픽 패턴을 보고 조정하는 편이 안전하다. 트래픽이 매우 적은 서비스에 과도하게 민감한 임계치를 쓰면 작은 흔들림에도 Open 상태가 반복되고, 반대로 트래픽이 큰 서비스에 임계치가 너무 느슨하면 차단이 늦어진다. 결국 브레이커는 코드보다 관측 데이터에 맞춘 운영 튜닝이 중요하다.
- 📢 섹션 요약 비유: 소방 문은 아무 때나 닫히면 곤란하지만, 불이 났는데도 안 닫히면 더 위험하듯 서킷 브레이커도 너무 예민하거나 너무 둔하면 둘 다 문제다.
Ⅴ. 기대효과 및 결론
서킷 브레이커를 잘 적용하면 장애를 없애지는 못해도, 장애가 확산되는 속도와 범위를 크게 줄일 수 있다. 사용자 입장에서는 끝없는 로딩 대신 빠른 실패와 대체 응답을 받고, 운영자 입장에서는 실패 원인을 더 분명하게 관측할 수 있다.
하지만 한계도 있다. 근본 원인이 해결되지 않으면 브레이커는 계속 열리고 닫히는 증상 관리에 머문다. 또 잘못 설계된 폴백은 실제 장애보다 더 큰 정합성 문제를 만들 수 있다. 따라서 서킷 브레이커는 만능 방패가 아니라, 타임아웃·재시도·벌크헤드·관측성과 함께 묶여야 효과가 나는 운영 패턴이다.
결론적으로 이 패턴의 핵심은 "실패를 막는다"가 아니라 "실패를 국소화한다"이다. 분산 시스템은 실패를 피할 수 없으므로, 무엇을 언제 끊을지 설계하는 쪽이 더 현실적이다. 좋은 서킷 브레이커는 장애를 숨기지 않고, 전체를 살리기 위해 일부 연결을 잠시 포기한다.
- 📢 섹션 요약 비유: 배 한 칸에 물이 새면 그 칸을 막아 나머지 배를 띄우는 것이 먼저이듯, 서킷 브레이커는 전체 서비스를 살리기 위해 일부 통로를 먼저 차단하는 선택이다.
📌 관련 개념 맵
| 개념 | 연결 포인트 |
|---|---|
| 타임아웃 (Timeout) | 기다림의 최대치를 정해 브레이커 이전 단계의 자원 낭비를 줄임 |
| 재시도 (Retry) | 일시적 오류 복구용이지만 과도하면 브레이커가 막아야 할 대상이 됨 |
| 벌크헤드 (Bulkhead) | 자원 풀 분리로 장애 범위를 서비스 내부에서도 제한 |
| 폴백 (Fallback) | Open 상태에서 사용자 경험을 보완하지만 정합성 검증이 필요 |
| 서비스 메시 (Service Mesh) | 프록시 계층에서 브레이커 정책을 공통 적용하는 대표 플랫폼 |
| 느린 호출 비율 (Slow Call Rate) | 실패 전 단계의 성능 저하를 조기 감지하는 지표 |
📈 관련 키워드 및 발전 흐름도
Remote call instability
│
▼
Timeout / Retry control
│
▼
Circuit Breaker state machine
│
├─ Open -> fail fast / fallback
├─ Half-Open -> probe recovery
└─ Closed -> normal traffic with metrics
│
▼
Bulkhead · Service Mesh · Resilience operations
이 흐름은 단순 원격 호출이 운영형 회복탄력성 제어 체계로 발전하는 과정을 보여 준다.
👶 어린이를 위한 3줄 비유 설명
- 친구 집 초인종이 고장 났는데 계속 누르면 모두 시끄럽고 힘들어져요.
- 서킷 브레이커는 "지금은 초인종 누르지 말고 잠깐 쉬자"라고 정해 주는 버튼이에요.
- 그래서 집이 다시 괜찮아졌는지 조금만 시험해 보고, 괜찮으면 다시 찾아가게 해 줘요.