안녕하세요. 자바파커입니다.
결제 서버 하나가 느려졌습니다. 주문 서버는 친절하게 세 번 재시도했습니다. 잠시 뒤 주문·재고·알림 서버까지 모두 느려졌습니다.
실패를 줄이려던 재시도가 왜 전체 장애를 만들었을까요?
서킷 브레이커는 실패를 없애는 장치가 아닙니다. 실패가 다른 서비스로 번지는 것을 막는 장치입니다.
요청이 쌓이다 차단기가 열리고, 시험 요청 하나로 복구를 확인하는 과정은 54초 영상으로 준비했습니다. 공개되면 이 자리에 연결합니다.
느린 실패가 더 위험한 이유
외부 서비스가 즉시 500을 반환하면 연결은 빨리 정리됩니다. 더 위험한 경우는 응답하지 않은 채 타임아웃까지 기다리는 상황입니다.
요청 1개
× 재시도 3회
× 각 타임아웃 3초
= 연결과 스레드가 오래 점유됨호출하는 서비스의 연결 풀과 작업 스레드가 먼저 고갈될 수 있습니다. 이후 정상 기능까지 자원을 얻지 못해 연쇄 장애가 발생합니다.
CLOSED — 평소에는 통과
CLOSED 상태에서는 요청을 원격 서비스로 보냅니다. 최근 실패 횟수나 비율을 기록하다 임계값을 넘으면 OPEN으로 전환합니다.
단 한 번의 실패로 여는 것은 보통 너무 민감합니다. 짧은 시간창 안의 실패 횟수·실패율·느린 호출 비율 등을 함께 봅니다.
OPEN — 원격 호출을 보내지 않는다
OPEN 상태에서는 요청을 실패 중인 서비스까지 보내지 않습니다.
- 즉시 오류 반환
- 캐시된 값 반환
- 축소된 기능 제공
- 비동기 처리로 전환
핵심은 빠른 실패입니다. 타임아웃까지 기다리지 않으므로 호출하는 서비스의 자원을 보호하고, 실패한 서비스에도 회복할 시간을 줍니다.
HALF-OPEN — 시험 요청만 통과
OPEN 상태에서 일정 시간이 지나면 요청 전체를 즉시 복구하지 않습니다. 제한된 시험 요청만 보내는 HALF-OPEN 상태로 바뀝니다.
- 시험 요청 성공 → 연속 성공 조건 후 CLOSED
- 시험 요청 실패 → 즉시 OPEN
갑자기 트래픽을 모두 되돌리면 막 회복한 서비스가 다시 쓰러질 수 있기 때문입니다.
Retry와 역할이 다르다
| 패턴 | 질문 |
|---|---|
| Timeout | 얼마나 기다릴까? |
| Retry | 일시적 실패를 다시 시도할까? |
| Circuit Breaker | 지금 호출 자체를 보내도 될까? |
Retry는 곧 성공할 가능성이 있는 일시적 실패를 다룹니다. Circuit Breaker는 계속 실패할 가능성이 높을 때 호출을 중단합니다. 둘을 함께 쓴다면 OPEN 신호를 받은 재시도 로직도 멈춰야 합니다.
상태는 어디까지 공유할까
인스턴스마다 독립적인 서킷 브레이커를 두면 구현은 단순하지만 각 인스턴스가 서로 다른 상태를 볼 수 있습니다. 반대로 상태를 중앙 공유하면 일관성은 높아지지만 네트워크·저장소 의존성이 하나 더 생깁니다.
대부분은 호출 대상·엔드포인트별로 로컬 상태를 두고, 상태 전환 이벤트와 지표를 중앙 모니터링에 모읍니다.
Fallback도 공짜가 아니다
OPEN 상태에서 기본값이나 캐시를 반환하면 사용자 경험은 좋아질 수 있습니다. 하지만 오래된 가격·재고·권한 정보를 반환하면 더 큰 문제가 됩니다.
fallback이 가능한 데이터와 반드시 실패해야 하는 작업을 구분해야 합니다. 결제 요청을 성공처럼 꾸미는 fallback은 허용할 수 없습니다.
무엇을 모니터링할까
- CLOSED·OPEN·HALF-OPEN 상태 전환 횟수
- 차단된 호출 수
- 실패율과 느린 호출 비율
- OPEN 유지시간
- HALF-OPEN 시험 요청 성공률
- fallback 사용량
상태 전환 이벤트는 장애 원인을 찾는 중요한 시간표가 됩니다.
정리
- CLOSED에서는 호출을 통과시키며 실패를 관찰합니다.
- 임계값을 넘으면 OPEN으로 바뀌어 빠르게 실패합니다.
- 대기시간 후 HALF-OPEN에서 소수 요청으로 회복을 시험합니다.
- Retry는 다시 시도하는 패턴이고 Circuit Breaker는 호출을 멈추는 패턴입니다.
장애가 난 서비스를 계속 두드리는 것은 복구 전략이 아닙니다.
자주 묻는 질문 (FAQ)
Timeout과 Circuit Breaker는 둘 다 필요한가요?
필요합니다. Timeout은 개별 호출을 얼마나 기다릴지 정하고, Circuit Breaker는 최근 실패가 누적됐을 때 호출 자체를 보낼지 결정합니다. Timeout이 없다면 느린 호출 하나가 오래 자원을 점유하고, Breaker가 없다면 실패할 호출을 매번 반복합니다.
Retry와 Circuit Breaker를 함께 써도 되나요?
함께 쓸 수 있지만 재시도 횟수와 간격을 제한해야 합니다. Breaker가 OPEN이면 Retry는 즉시 중단하고, 일시 오류에만 지수 백오프와 지터를 적용해야 장애 중인 서비스에 재시도 폭풍을 만들지 않습니다.
실패율 임계값은 몇 퍼센트가 적당한가요?
정답은 없습니다. 호출량, 정상 오류율, 지연 시간, 사업 영향에 따라 달라집니다. 낮은 트래픽에서는 최소 호출 수를 먼저 채운 뒤 실패율을 계산하고, 실패율뿐 아니라 느린 호출 비율도 함께 관찰하는 것이 안전합니다.