Skip to Content
Software Architecture외부 장애가 내부 서비스로 전파되지 않게 막는 방법
🏗️ Software Architecture2021년 9월 6일

외부 장애가 내부 서비스로 전파되지 않게 막는 방법

#e-commerce#nike-korea-migration#operations#security#software-architecture
Nike Korea Platform Migration · Series 4 - 운영 안정성과 보안5 / 6Software Architecture
현대의 서비스는 혼자 동작하지 않는다. 결제 게이트웨이, 배송 추적 API, 알림 서비스, 외부 인증 시스템 등 수많은 외부 의존성(dependency)이 있다. 이 외부 서비스 중 하나가 장애를 일으키면, 그 장애

현대의 서비스는 혼자 동작하지 않는다. 결제 게이트웨이, 배송 추적 API, 알림 서비스, 외부 인증 시스템 등 수많은 외부 의존성(dependency)이 있다. 이 외부 서비스 중 하나가 장애를 일으키면, 그 장애가 내부 서비스로 전파(propagation)되어 전체 시스템이 멈추는 카스케이딩 실패(cascading failure)가 발생할 수 있다.

외부 장애 자체는 막을 수 없지만, 장애 반경은 설계로 제한할 수 있다. 핵심은 호출 실패를 빠르게 격리하고 핵심 주문 경로를 보호하는 것이다.

이 글은 Breeze 플랫폼에서 외부 장애 전파를 방지하기 위해 적용한 패턴들 — circuit breaker, timeout, fallback, bulkhead — 을 기록한다. 이론적인 패턴 설명이 아니라, 실제 운영에서 이 패턴들이 어떻게 동작했고 어떤 trade-off가 있었는지를 중심으로 기술한다.

외부 장애는 예측할 수 없고 통제할 수도 없다. 통제할 수 있는 것은 우리 서비스가 외부 장애에 어떻게 반응하는지뿐이다. 이 관점에서의 설계 경험을 남긴다.

Breeze 플랫폼은 여러 외부 서비스와 통합되어 있었다. 결제 PG(Payment Gateway)는 결제 처리를, 배송 API는 배송 상태 추적을, SMS/이메일 서비스는 알림 발송을, 외부 인증(OAuth 등)은 로그인 처리를 담당했다. 이 외부 서비스들은 각각 독립적인 가용성과 성능 특성을 가지고 있다.

외부 서비스가 느려지거나 응답하지 않을 때, 내부 서비스의 스레드가 외부 응답을 기다리며 점유(block)된다. 동시 요청이 많아지면 스레드 풀이 고갈되고, 외부 서비스와 무관한 다른 기능까지 영향을 받는다. 예를 들어, 배송 추적 API가 느려져서 상품 조회까지 느려지는 상황이 발생할 수 있다.

이 문제는 마이크로서비스 아키텍처에서 더욱 심각해진다. 서비스 간 호출 체인이 길어질수록, 체인 중 하나의 지연이 전체 응답 시간을 지배하게 된다. Breeze는 모놀리식에 가까웠지만, 외부 서비스 통합 지점에서 동일한 문제가 발생했다.

Timeout 설정: 기다림의 한계를 정하라

가장 기본적이면서도 중요한 방어는 timeout 설정이다. 외부 서비스 호출 시 무한정 기다리지 않고, 지정된 시간 내에 응답이 오지 않으면 호출을 포기(abort)하는 것이다. timeout 없이 외부 서비스를 호출하면, 외부 서비스가 응답하지 않을 때 내부 스레드가 무한히 점유되어 서비스 전체가 멈출 수 있다.

timeout 값 설정은 trade-off다. 너무 짧으면 정상적이지만 약간 느린 응답을 타임아웃 처리하여 불필요한 실패가 발생한다. 너무 길면 외부 장애 시 스레드 점유 시간이 길어져 방어 효과가 떨어진다. 일반적으로 외부 서비스의 평상시 P99 응답시간에 약간의 여유를 더한 값을 timeout으로 설정했다. 결제 PG처럼 응답이 느린 서비스는 timeout을 길게, 캐시 조회처럼 빨라야 하는 서비스는 짧게 설정했다.

실무 적용 순서

Timeout 기준 고정

외부 호출별 P99 기반 timeout을 먼저 정하고 무한 대기를 제거한다.

Circuit Breaker 적용

연속 실패 임계치와 HALF-OPEN 복구 조건을 서비스별로 설정한다.

Bulkhead 분리

외부 연동별 스레드/커넥션 풀을 분리해 장애 반경을 제한한다.

Fallback/Retry 튜닝

기능 축소 응답과 backoff 재시도를 결합해 사용자 영향과 부하를 동시에 제어한다.

Circuit Breaker: 실패를 빠르게 인정하라

circuit breaker 패턴은 외부 서비스의 실패가 일정 횟수 이상 반복되면, 더 이상 호출을 시도하지 않고 즉시 실패를 반환하는 것이다. 전기 회로의 차단기(circuit breaker)와 같은 원리다. CLOSED(정상) → OPEN(차단) → HALF-OPEN(시험) 상태를 거치며, OPEN 상태에서는 외부 호출 없이 즉시 에러를 반환한다.

circuit breaker가 없으면, 이미 장애가 발생한 외부 서비스에 계속 요청을 보내게 된다. 이 요청들은 모두 timeout까지 기다린 후 실패하므로, 내부 리소스를 무의미하게 소모한다. circuit breaker는 이 무의미한 재시도를 빠르게 중단하여 내부 리소스를 보호한다. HALF-OPEN 상태에서 주기적으로 한 건씩 시험 호출을 보내, 외부 서비스가 복구되었는지를 확인한다.

Fallback: 장애 시 대안을 제공하라

circuit breaker가 열리거나 timeout이 발생했을 때, 사용자에게 어떤 경험을 제공할 것인가가 fallback 전략이다. 무조건 에러를 보여주는 것이 아니라, 가능한 범위에서 서비스를 유지하는 것이 graceful degradation이다.

예를 들어, 배송 추적 API가 장애인 경우 ‘배송 상태를 현재 확인할 수 없습니다. 잠시 후 다시 시도해주세요’라는 메시지를 보여주되, 나머지 기능(상품 조회, 장바구니, 결제)은 정상적으로 제공한다. 또는 캐시된 마지막 배송 상태를 보여줄 수도 있다. 핵심은 하나의 외부 장애가 전체 사용자 경험을 파괴하지 않도록 하는 것이다.

Bulkhead 패턴: 장애 영역을 격리하라

bulkhead 패턴은 선박의 격벽(bulkhead)에서 유래한다. 선박이 침수되어도 격벽이 있으면 침수가 다른 구역으로 확산되지 않는다. 소프트웨어에서는 스레드 풀을 외부 서비스별로 분리하여, 하나의 외부 서비스가 느려져도 다른 외부 서비스의 호출에 영향을 주지 않게 한다.

모든 외부 호출이 하나의 공유 스레드 풀을 사용하면, 결제 PG가 느려져서 스레드를 점유하면 배송 추적이나 알림 발송도 스레드를 할당받지 못해 함께 느려진다. 서비스별로 별도 스레드 풀을 사용하면 결제 PG의 문제가 다른 외부 서비스 호출에 영향을 주지 않는다.

Retry with Exponential Backoff

일시적 장애(transient failure)에 대응하기 위한 재시도(retry) 전략도 중요했다. 단순 재시도는 위험하다 — 외부 서비스가 과부하 상태일 때 즉시 재시도하면 부하를 가중시킨다. exponential backoff(1초, 2초, 4초, 8초 등 점점 간격을 늘려 재시도)를 적용하면 외부 서비스가 복구될 시간을 주면서도 재시도의 이점을 유지할 수 있다.

재시도에는 jitter(임의 지연)를 추가하는 것도 중요하다. 여러 클라이언트가 동시에 같은 backoff 간격으로 재시도하면 동시 요청(thundering herd)이 발생하여 외부 서비스에 다시 과부하를 줄 수 있다. jitter를 추가하면 재시도 시점이 분산된다.

실제 사례: Breeze 운영에서의 경험

Breeze 운영 중 외부 PG의 간헐적 장애가 발생했을 때, timeout과 circuit breaker 덕분에 결제 외의 다른 기능(상품 조회, 검색, 장바구니 추가 등)은 정상적으로 유지되었다. PG가 복구되면 circuit breaker가 HALF-OPEN에서 CLOSED로 전환되어 결제도 자동으로 복구되었다. 이 자동 복구가 가능한 것은, 수동 개입 없이 시스템이 외부 서비스의 상태를 감지하고 적응하기 때문이다.

패턴 조합 가이드

상황우선 적용 패턴보조 패턴
지연 증가 중심 장애Timeout, BulkheadRetry with backoff
연속 실패/다운Circuit BreakerFallback
트래픽 급증과 외부 불안정 동시Bulkhead, Circuit BreakerJitter 포함 Retry

운영 안정성과 보안은 개별 도구의 문제가 아니라 개발 흐름과 운영 기준을 바꾸는 구조적 작업이었다. 다음 글에서는 2021 - 운영 비용 최적화는 왜 인프라 절감보다 구조 문제에 가깝나를 통해 이 흐름을 계속 좁혀 본다.

패턴 적용의 장단점

timeout, circuit breaker, bulkhead, retry 같은 패턴은 장애 전파를 막는 데 효과적이지만, 동시에 구성 파라미터와 관측 포인트를 늘린다. 즉 안정성을 얻는 대신 설정 복잡도를 감수해야 한다.

그래서 패턴 도입의 핵심은 “많이 넣는 것”이 아니라 “실패 양상에 맞게 최소 세트를 정확히 적용하는 것”이었다. 어떤 외부 호출에 어떤 보호 장치를 둘지 명확히 정의하면, 운영 복잡도를 통제하면서도 장애 반경을 크게 줄일 수 있다.

외부 연동 보호 패턴 체크포인트

  • 호출별로 timeout, retry, circuit breaker, bulkhead를 개별 설정한다.
  • 실패율/지연시간 지표를 기준으로 차단 임계치를 환경별로 튜닝한다.
  • fallback 응답은 기능 축소를 허용하되 핵심 주문 경로는 보호한다.

패턴 선택 가이드

패턴주효한 상황주의점
Timeout + Retry일시적 지연/네트워크 오류과도한 재시도로 증폭 가능
Circuit Breaker연속 실패/의존 서비스 다운임계치 튜닝 실패 시 오차단
Bulkhead특정 연동 과부하스레드/풀 관리 복잡도 증가
Last updated on