분산 시스템에서 호출은 실패합니다. backoff를 사용한 retry는 일시적 오류에서 복구하고, circuit breaker는 정말로 다운된 dependency를 계속 두드리는 것을 막습니다. 둘은 상호 보완적입니다: 일시 장애는 retry하고, 지속 장애에는 회로를 끊습니다.
exponential backoff + jitter를 사용한 retry
일시적 실패(timeout, 짧은 네트워크 장애, 503)에는 retry하되, 지수적으로 backoff하고 jitter를 더해 retry가 동기화되어 thundering herd로 몰리지 않고 분산되게 합니다.
text
시도 1 → ~1s 대기 (+ 무작위 jitter)
시도 2 → ~2s 대기 (+ 무작위 jitter)
시도 3 → ~4s 대기 (+ 무작위 jitter)
→ maxRetries(예: 3)와 최대 delay에서 상한 → 영원히 retry하지 말 것
핵심 주의사항:
- retry 상한 설정 — 무한 retry는 복구 중인 서비스를 과부하시키는 retry storm을 만듦.
- Idempotency — 반복해도 안전한 작업만 retry (retry된 결제가 두 번 청구되면 안 됨).
- Jitter — 없으면 모든 클라이언트가 같은 순간에 retry하여 부하를 다시 급증시킴.
circuit breaker
circuit breaker는 dependency로의 실패를 추적하고, 임계치를 넘으면 open으로 trip되어 — 죽은 서비스를 호출하는 대신 빠르게 실패(또는 fallback 반환)합니다. cooldown 후에는 half-open으로 전환되어 복구를 탐색합니다.
text
CLOSED → 호출이 통과; 실패 횟수 카운트
실패 과다 → trip → OPEN
OPEN → 즉시 빠르게 실패 (호출 없음); cooldown 타이머 시작
cooldown 경과 → HALF-OPEN
HALF-OPEN → 몇 개의 탐색 호출 허용
성공 → CLOSED (복구됨) ; 실패 → 다시 OPEN
각각 언제 쓰는가
text
Retry → 일시적이고 곧 성공할 가능성이 높은 오류 (느린 호출 1건)
Circuit breaker → 반복적/지속적 실패 (dependency가 다운됨)
→ 함께 사용: breaker가 죽은 서비스 위에 retry가 쌓이는 것을 막음
왜 중요한가
이것들이 없으면 실패한 dependency 하나가 호출자까지 함께 끌고 내려갑니다: 요청이 timeout으로 쌓이고, retry가 부하를 증폭하며, 실패가 서비스 전반으로 cascade됩니다. jitter를 더한 exponential backoff는 retry storm 없이 일시 장애에서 복구하고, 상한과 idempotency는 retry를 안전하게 유지하며, circuit breaker는 죽은 dependency에 자원을 낭비하지 않고 복구할 여유를 줍니다. 함께라면 dependency 실패를 격리되고 자가 치유되는 사건으로 바꿉니다.
