외부 본인인증 API 지연이 결제·장바구니까지 연쇄 장애로 번진 팀의 포스트모템 케이스다. 타임아웃·재시도 핫픽스, 워커 분리, 회로 차단기(Circuit Breaker) Closed·Open·Half-Open 임계값, 폴백·메트릭·기능 플래그 롤아웃 전후 숫자를 정리한다. 백엔드·API·개발자·Sentry·구조화 로깅·Rate limiting 연계 가이드.
화요일 11:14, 결제 확인 API의 p99 응답이 180ms에서 12초로 뛰었다. 원인은 우리 서버가 아니라 파트너 본인인증 API였다. 그런데 팀 전체 장애 티켓은 결제·장바구니·알림까지 네 개 서비스에 동시에 열렸다.
외부 의존성 하나가 느려졌을 뿐인데, 내부 스레드 풀이 전부 그 호출에 묶였고 나머지 요청은 줄 서서 타임아웃으로 죽었다. 이 글은 B2B 결제·인증 연동 팀이 재시도만 늘리다가 장애를 키운 뒤, 회로 차단기(Circuit Breaker)로 의존성을 격리하기까지의 문제·시도·결과를 시간순으로 복원한 케이스다. 기업명과 일부 수치는 익명 처리했다.
※ 2026년 상반기 포스트모템·런북 초안을 바탕으로 재구성. 수치·시각은 교육용으로 단순화.
무엇이 깨졌나 | 11:14~12:40 타임라인
서비스는 Node.js API 게이트웨이 뒤에서 결제 확인, 본인인증 프록시, 알림 발송을 묶었다. 국내 카드·간편결제와 본인인증 벤더 HTTP API 한 곳에 의존했고, 타임아웃은 기본 30초, 재시도는 실패 시 즉시 2회였다.
시각
사건
체감 영향
11:14
벤더 p99 지연 급증 (내부 메트릭)
결제 확인만 느려짐
11:18
게이트웨이 동시 연결 상한 80% 돌파
장바구니 조회도 대기
11:22
재시도 폭주 (요청당 최대 3회)
벤더 QPS 3배, 우리 스레드 고갈
11:31
5xx 비율 42%
슬랙 온콜 호출
11:55
인스턴스 스케일 아웃 2배
대기 요청만 늘고 회복 없음
12:40
벤더 측 복구 + 트래픽 수동 차단
약 86분 부분 장애
장애 구간 동안 결제 성공률은 정상의 38% 수준으로 떨어졌다. 본인인증과 무관한 읽기 API까지 함께 느려진 점이 포스트모템 1순위 질문이었다.
외부 지연이 내부 대기열로 전이되는 구조 (개념 다이어그램)
원인 분해 | 벤더 장애가 아니라 전파 구조
벤더는 그날 일부 리전에서 지연을 인정했다. 다만 팀이 겪은 전면 체감 저하는 전파 설계 쪽 비중이 컸다.
긴 타임아웃 — 30초 대기는 사용자 체감보다 스레드 점유에 치명적이다. 요청 하나당 최대 90초(재시도 포함) 점유 가능.
무조건 재시도 — 5xx·타임아웃에 즉시 재시도하면 실패 트래픽을 스스로 3배로 만든다. Rate limit 글에서 다루는 백프레셔와 같은 방향이다, 외부 호출에도 그대로 적용된다. 관련: 프로덕션 API Rate Limiting 설계.
공유 워커 풀 — 인증 프록시와 장바구니 조회가 같은 프로세스·같은 이벤트 루프 부하 한도에 묶여 있었다. 격리 큐가 없었다.
폴백 없음 — 벤더가 죽으면 즉시 5xx. 캐시된 최근 인증 상태나 "나중에 재확인" 플로우가 없었다.
Redis 캐시 스탬피드 사례와 닮은 점이 있다. 단일 의존성이 정상이 아닐 때 재시도·재조회가 오히려 부하를 키운다. 참고: Redis 캐시 장애 대응 72시간.
포스트모템 한 줄: "외부 장애를 막을 수는 없었다. 내부 전체가 같이 쓰러진 것은 막을 수 있었다."
시도 1 | 타임아웃 단축과 재시도 제거
당일 오후 핫픽스는 단순했다. 타임아웃 30초→3초, 재시도 2회→0회. 배포 후 p99는 즉시 내려갔고, 스레드 점유도 줄었다.
다만 부작용이 바로 나왔다. 벤더가 간헐적으로 2~3초 경계에서 응답하는 정상 구간에서도 실패율이 올라갔다. 고객 상담 티켓에 "본인인증 실패가 늘었다"가 쌓였다. 숫자만 보면 장애 시간은 줄었지만, 성공해야 할 요청까지 잘라낸 상태였다.
팀은 다음 날 타임아웃을 5초로 다시 올리고, 재시도는 멱등 GET에만 1회·지터 백오프로 제한했다. 이 단계는 응급 지혈이지 구조 해결이 아니었다.
시도 2 | 인스턴스 늘리기와 큐 분리
스케일 아웃은 장애 중에도 시도됐다. 인스턴스를 2배로 올리면 대기 요청을 더 받을 수 있을 거라는 가정이다. 결과적으로 벤더로 가는 동시 호출만 늘었고, 복구 시점은 거의 변하지 않았다.
사후 조치로 인증 프록시를 별도 워커 프로세스로 분리했다. 게이트웨이는 인증 호출을 짧은 내부 RPC로 넘기고, 인증 워커만 벤더 HTTP를 담당한다. 장바구니·상품 조회는 인증 워커가 포화돼도 직접 영향이 줄었다.
3주차에 회로 차단기를 붙였다. 라이브러리는 런타임에 맞춰 opossum(Node) 계열을 썼고, 개념은 마틴 파울러의 Circuit Breaker 패턴과 동일하다. 상태는 세 가지다.
상태
동작
전환 조건(이 팀 값)
Closed
정상 호출
최근 60초 실패율 < 50%
Open
즉시 실패(호출 안 함)
실패율 ≥ 50% 또는 연속 실패 20
Half-Open
소수 프로브만 통과
Open 후 30초 경과
Open 상태에서는 벤더를 때리지 않고 로컬 폴백을 탄다. 최근 성공 인증 토큰이 캐시에 있으면 짧은 유예 창을 주고, 없으면 사용자에게 "잠시 후 재시도"와 대체 채널(고객센터 확인 코드)을 안내한다. 실패를 숨기지 않고, 대기 자원만 지키면서 실패를 빠르게 확정하는 것이 목표였다.