API Circuit Breaker 패턴 (장애 보호, 지연 증가, 복구 전략)

Circuit Breaker를 처음 도입할 때 이게 만능 해결책인 줄 알았습니다. 외부 API 장애가 시스템 전체를 마비시키는 상황을 몇 번 겪고 나니 "이거 하나만 적용하면 끝"이라고 생각했거든요. 그런데 막상 운영해보니 생각보다 복잡했습니다. 장애는 막았는데 정상 요청까지 차단되는 경우가 생기더군요. 실패 기준을 어떻게 설정하느냐에 따라 시스템이 너무 예민해지거나 반대로 둔감해지는 문제가 반복됐습니다. 이 글에서는 제가 현장에서 직접 겪은 Circuit Breaker의 양면성과 실제 적용 과정에서 마주친 문제들을 데이터와 함께 정리해봤습니다.

장애 보호 메커니즘과 실제 효과

Circuit Breaker의 핵심 기능은 장애가 발생한 서비스로의 요청을 차단하여 연쇄 장애를 막는 것입니다. 분산 시스템에서는 하나의 서비스가 응답하지 않으면 이를 호출하는 상위 서비스도 대기 시간이 길어지면서 스레드 풀이 고갈되는 문제가 발생합니다. 이런 상황이 반복되면 전체 시스템이 연쇄적으로 마비될 수 있습니다.

제가 운영했던 시스템에서는 외부 결제 API 하나가 다운되자 내부 주문 서비스까지 타임아웃이 연쇄적으로 발생했습니다. 당시 모니터링 데이터를 확인해보니 응답 시간이 평소 200ms에서 15초 이상으로 치솟았고, 전체 요청의 약 70%가 실패 상태였습니다. Circuit Breaker를 도입한 후에는 실패율이 5% 이하로 떨어졌습니다. 회로가 열리면서 장애 서비스로의 요청이 즉시 차단됐고, 나머지 시스템은 정상 작동을 유지할 수 있었습니다.

Circuit Breaker는 크게 세 가지 상태로 동작합니다. Closed 상태에서는 모든 요청이 정상적으로 통과하고, 일정 실패 횟수(threshold)를 초과하면 Open 상태로 전환되어 요청을 차단합니다. 그리고 일정 시간이 지나면 Half-Open 상태로 넘어가 일부 요청만 허용하면서 서비스 복구 여부를 확인합니다. 이 메커니즘 덕분에 장애 서비스에 대한 불필요한 자원 낭비를 막고 전체 시스템의 가용성을 확보할 수 있습니다.

지연 증가와 정상 요청 차단 문제

그런데 실제로 써보니 Circuit Breaker가 열려 있는 동안에는 정상적인 요청도 함께 차단되는 문제가 발생했습니다. 회로가 Open 상태일 때는 실제로 외부 서비스가 복구되었더라도 설정된 시간이 지나야만 Half-Open으로 전환되기 때문입니다. 이 시간 동안 사용자는 서비스를 이용할 수 없고, 이는 결국 지연이나 실패로 인식됩니다.

이 부분이 가장 민감한 설정이었습니다. 초기에는 실패 기준을 5회, 차단 시간을 30초로 설정했는데 일시적인 네트워크 지연에도 회로가 자주 열렸습니다. 실제 장애가 아닌 경우에도 30초 동안 모든 요청이 막히니 고객 불만이 급증했습니다. 반대로 기준을 너무 느슨하게 설정하면 장애 상황에서도 회로가 열리지 않아 연쇄 장애를 막지 못했습니다.

이 문제를 해결하기 위해 저희 팀은 실패율 기반 판단 방식으로 전환했습니다. 절대 실패 횟수 대신 최근 100건의 요청 중 실패율이 50%를 넘으면 회로를 여는 방식입니다. 또한 차단 시간도 10초로 줄이고 Half-Open 상태에서 3건의 테스트 요청을 보내 2건 이상 성공하면 Closed로 복구하도록 설정했습니다. 이렇게 정책을 조정한 후 정상 요청 차단 비율이 약 80% 감소했습니다.

  1. 실패 기준: 절대 횟수보다 실패율(%) 기반으로 판단
  2. 차단 시간: 10~30초 범위에서 서비스 특성에 맞게 조정
  3. Half-Open 테스트: 일부 요청만 허용하여 점진적 복구 확인
  4. Fallback 응답: 회로 차단 시 캐시된 데이터나 기본값 제공

복구 전략과 정책 설계의 중요성

Circuit Breaker는 단순히 요청을 차단하는 기능이 아니라 정교한 복구 전략이 함께 설계되어야 제대로 동작합니다. Half-Open 상태는 이 전략의 핵심입니다. 회로가 열린 후 일정 시간이 지나면 시스템은 소수의 테스트 요청을 보내 서비스가 실제로 복구되었는지 확인합니다. 이 과정에서 성공률이 기준을 충족하면 Closed 상태로 전환하고, 여전히 실패하면 다시 Open 상태로 돌아갑니다.

제가 담당했던 프로젝트에서는 Half-Open 상태에서 허용할 테스트 요청 수와 성공 기준을 여러 번 조정했습니다. 처음에는 1건만 보내고 성공하면 복구하는 방식이었는데, 우연히 한 번 성공한 후 바로 회로를 닫았다가 다시 장애가 발생하는 경우가 반복됐습니다. 이후 테스트 요청을 5건으로 늘리고 그중 3건 이상 성공해야 복구하도록 변경하니 안정성이 크게 향상됐습니다.

또한 중요한 요청에 대해서는 fallback 응답을 제공하는 전략도 함께 적용했습니다. 예를 들어 상품 상세 정보를 외부 API에서 가져오는 경우 회로가 열리면 캐시된 데이터를 반환하도록 설정했습니다. 완벽한 최신 정보는 아니지만 사용자가 아무것도 볼 수 없는 상황보다는 훨씬 나았습니다. 실제로 이 방식을 도입한 후 장애 상황에서도 서비스 이용률이 약 60% 유지됐습니다.

일반적으로 Circuit Breaker를 도입하면 모든 문제가 해결될 것이라고 생각하는 분들도 있는데, 실제로 써보니 정책 설계가 더 중요했습니다. 실패 기준, 차단 시간, Half-Open 복구 조건, fallback 전략까지 모든 요소가 서비스 특성에 맞게 조정되어야 합니다. 특히 금융이나 결제처럼 실시간성이 중요한 도메인에서는 차단 시간을 짧게 가져가고 Half-Open 전환을 빠르게 하는 것이 유리합니다. 반대로 배치 작업처럼 지연이 허용되는 경우에는 좀 더 여유 있게 설정해도 무방합니다.

결국 Circuit Breaker는 장애를 막는 동시에 서비스 가용성을 최대한 유지하는 균형점을 찾는 작업입니다. 이 패턴을 도입하면서 시스템 안정성이 크게 향상되는 경험을 했지만, 동시에 정책 설계 없이는 오히려 사용자 경험을 해칠 수 있다는 점도 배웠습니다. 만약 Circuit Breaker 도입을 고민 중이라면 먼저 여러분의 서비스가 어느 정도의 지연과 실패를 허용할 수 있는지, 장애 복구에 얼마나 시간이 걸리는지 데이터를 수집해보시길 권합니다. 그 데이터를 바탕으로 정책을 설계하고 운영 환경에서 조금씩 조정해나가는 것이 가장 확실한 방법입니다.

댓글

이 블로그의 인기 게시물

HTTP 메서드의 필요성 (GET과 POST, PUT과 DELETE, API 보안)

API 없는 세상의 불편함 (로그인 연동, 서비스 구조, 디지털 인프라)

API 이해하기 (서비스 연결, 시스템 협력, 디지털 구조)