캐스케이딩 장애에서 리트라이는 왜 복구를 늦추는가?
원인은 서버 다운 그 자체가 아니라 동기화된 재시도다. 다운스트림이 잠깐 회복되려는 순간, 동시에 몰린 재시도가 그 회복 경로를 다시 누른다. 해법은 재시도를 없애는 게 아니라 CircuitBreaker·지수 백오프·지터·벌크헤드를 하나의 세트로 묶어 재시도 조건을 설계하는 것이다. 2026년 기준으로도 이 조합 밖에 "정답 수치"는 공개되어 있지 않다.
- 리트라이 폭풍의 재현 조건은 CircuitBreaker 없이 Retry만 있고, 재시도 간격에 지터가 없는 상태다.
- 지수 백오프만으로는 부족하다. 배수 간격이 커져도 실패 시점이 같으면 재시도는 여전히 겹친다.
- 재발 방지는 "재시도 허용"이 아니라 "재시도 조건 설계"다: maxAttempts를 작게, backoff는 증가형, jitter는 필수, breaker가 열리면 재시도 자체를 차단.
- 장애 복원은 서비스가 응답을 재개하는 순간이 아니라, 재시도 폭풍이 멈추고 원인 전파가 차단된 순간에 끝난다.
이 글은 결제 게이트웨이 장애를 모델 사례로 두고, 클라이언트 재시도 계층부터 서킷브레이커·백오프·벌크헤드까지 HTTP/RPC 요청 경로만 해부한다. 전력선·케이블 절단 같은 인프라 계층 원인은 전파 구조를 보여주는 참고 사례로만 인용하고, 해부 대상에서는 제외한다.
재시도가 동기화되는 지점은 어디인가?
다수 클라이언트가 같은 실패 이벤트를 같은 시각에 겪고, 고정 간격으로 재시도할 때 동기화가 발생한다. 결제 게이트웨이 모델에서는 waitDuration=1s로 고정한 재시도가 다수 클라이언트에서 동시에 발화하는 상황을 재현 조건으로 삼는다. 이 시점에서는 실패율이 아니라 "요청이 몇 초 간격으로 뭉치는가"가 핵심 관찰 대상이다.
서킷브레이커는 언제 열려야 하는가?
실패율이 임계치를 넘는 즉시 열려서 재시도 자체를 차단해야 한다. Breaker가 열린 상태에서는 클라이언트가 다운스트림에 요청을 보내지 않고 즉시 실패하거나 degraded result를 반환한다. Half-open 상태에서 소수 요청만 통과시켜 회복 여부를 확인하는 방식이 표준적인 흐름이다. Google SRE는 장애를 숨기지 말고 격리해야 한다고 정리하는데, breaker의 역할이 정확히 이 "격리"에 해당한다.
지수 백오프에 지터를 더하면 파형이 어떻게 바뀌는가?
지수 백오프만 쓰면 배수 간격은 늘어나지만 실패 시점이 같은 클라이언트들의 재시도는 여전히 같은 타이밍에 겹칠 수 있다. 여기에 randomizedWaitFactor 같은 지터를 더하면 재시도가 시간축 위에 흩어진다. InfoQ는 이를 재시도 파형을 "smear"한다고 표현하며, 동시에 짧은 시간 내 재시도 횟수 자체를 제한해야 한다고 덧붙인다.
벌크헤드와 로드셰딩은 재시도 폭풍과 어떻게 맞물리는가?
재시도가 공유 스레드풀이나 커넥션 풀을 점유하면, 실패한 요청뿐 아니라 정상 요청까지 자원을 못 받는다. 벌크헤드는 이 풀을 서비스별로 분리해 한 곳의 재시도 폭증이 전체 복구 경로를 먹지 못하게 만든다. 로드셰딩은 풀이 이미 찬 상태에서 들어오는 초과 트래픽을 아예 받지 않고 버린다. 이 두 장치가 없으면 breaker와 jitter만으로는 공유 자원 경쟁을 막지 못한다.
설정값을 바꾸면 실제로 무엇이 달라지는가?
결제 게이트웨이 재현 모델의 설정 조합은 maxAttempts=3, waitDuration=1s, exponentialBackoffMultiplier=2, randomizedWaitFactor=0.5다. 이 조건에서 관찰해야 할 것은 처리량 수치가 아니라 "재시도가 동시에 발화하는 빈도"와 "breaker가 열려 있는 구간의 길이"다. 현재 공개된 자료에는 이 조합이 처리량을 몇 퍼센트 개선했다는 정량 수치는 확인되지 않는다. 대신 가설을 로그로 세우고 재현 실험과 카나리로 검증하는 방식이 실측 대체 수단으로 제시된다. 판단 기준은 "동시 재시도 발생 여부, retry 간격, jitter 유무, breaker 상태, 다운스트림 회복 시간, 스레드풀 한계"라는 조건 목록이지, 단일 숫자가 아니다.
이 조합은 무엇을 얻고 무엇을 잃는가?
얻는 것은 2차 장애 방지와 원인 전파 차단 시점의 명확화다. Breaker가 열려 있는 구간과 jitter로 흩어진 재시도 구간이 분리되면, 복구가 "서비스 응답 재개" 시점이 아니라 "재시도 폭풍 종료" 시점으로 재정의된다. 잃는 것은 응답 지연과 단기 성공률이다. Backoff 대기와 fail fast 정책은 일부 요청을 즉시 포기하거나 degraded result로 돌려보낸다. 또한 maxAttempts·waitDuration·multiplier·randomizedWaitFactor·breaker threshold를 함께 튜닝해야 하므로 운영 복잡도가 늘어난다. 파라미터가 늘어난 만큼 모니터링 대상도 늘어난다.
이 복원 방식은 언제 쓰고 언제 쓰지 않아야 하는가?
다운스트림 의존성이 반복적으로 실패하고, 짧은 시간에 트래픽이 급증할 수 있는 구조라면 이 조합을 기본값으로 둘 근거가 있다. 반대로 단발성 배치 작업이나, 쓰기 작업이 idempotent하지 않아 재시도 자체가 위험한 경로에서는 breaker와 jitter를 두는 것보다 재시도를 원천적으로 금지하는 편이 안전하다. 실시간 응답 SLA가 매우 엄격한 경로에서는 backoff 대기 자체가 SLA 위반이 될 수 있으므로, 이 경우엔 재시도 대신 즉시 fail fast와 대체 경로 전환을 우선한다.
핵심 정리
- 리트라이 폭풍의 본질은 서버 다운이 아니라 동기화된 재시도가 복구 경로를 다시 누르는 것이다.
- 지수 백오프 단독으로는 부족하고, jitter로 재시도 파형을 시간축에 흩어야 한다.
- CircuitBreaker·백오프·jitter·벌크헤드는 세트로 묶어야 하며, 단독 장치로는 전파를 막지 못한다.
- 실측 수치보다 재현 조건(동시성, breaker 상태, 회복 시간, 풀 한계)을 기록하는 것이 사후분석의 핵심 자산이다.
- 복원의 종료 시점은 서비스 응답 재개가 아니라 재시도 폭풍 종료와 원인 전파 차단 시점이다.
참고 자료
더 알아보기
장애 사후분석: 타임라인·근본원인·재발 방지의 방법론 — 이 주제의 종합 가이드