서킷 브레이커(Circuit Breaker)
마이크로서비스 아키텍처(MSA)에서 특정 서비스에 장애가 발생했을 때 아무런 조치가 없다면 게이트웨이는 계속 요청을 보내고, 스레드는 대기하다 고갈되며 시스템 전체가 멈추는 연쇄 장애로 이어진다.
서킷 브레이커(Circuit Breaker) 패턴을 도입해 문제가 생긴 서비스로 가는 경로를 차단 후 대체 경로로 안내해 시스템을 보호한다.
의존성 추가(build.gradle)
dependencies {
implementation 'org.springframework.cloud:spring-cloud-starter-gateway'
implementation 'org.springframework.cloud:spring-cloud-starter-circuitbreaker-reactor-resilience4j'
implementation 'org.springframework.cloud:spring-cloud-starter-loadbalancer'
}
ResilienceConfig
package com.example.distributed.config;
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
import io.github.resilience4j.timelimiter.TimeLimiterConfig;
import org.springframework.cloud.circuitbreaker.resilience4j.ReactiveResilience4JCircuitBreakerFactory;
import org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JConfigBuilder;
import org.springframework.cloud.client.circuitbreaker.Customizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.time.Duration;
@Configuration
public class ResilienceConfig {
@Bean
public Customizer<ReactiveResilience4JCircuitBreakerFactory> defaultCustomizer() {
return factory -> factory.configureDefault(id -> new Resilience4JConfigBuilder(id)
.circuitBreakerConfig(CircuitBreakerConfig.custom()
.slidingWindowSize(10)
.failureRateThreshold(50)
.waitDurationInOpenState(Duration.ofSeconds(10))
.build())
.timeLimiterConfig(TimeLimiterConfig.custom()
.timeoutDuration(Duration.ofSeconds(4))
.build())
.build());
}
}
서킷 브레이커 정책 설정
어떤 상황에서 경로를 차단할지 구체적인 규칙을 정의합니다.
- Sliding Window (10): 최근 10개의 요청을 기준으로 장애율을 계산
- Failure Rate Threshold (50%): 요청 중 50% 이상이 실패하면 서킷을 열어(Open) 요청을 즉시 차단
- Wait Duration (10초): 서킷이 열린 후 10초간 대기하며 서비스를 보호한 뒤, 다시 연결을 시도(Half-open)
- Time Limiter (4초): 응답이 4초 이상 걸리면 강제로 타임아웃 처리하여 스레드 점유를 방지
FallbackController
package com.example.distributed.controller;
// ... (필요한 import 생략)
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/fallback")
public class FallbackController {
@GetMapping("/externalService")
public ResponseEntity<Map<String, Object>> externalServiceFallback() {
Map<String, Object> response = new HashMap<>();
response.put("success", false);
response.put("message", "현재 시스템 부하로 인해 요청을 처리할 수 없습니다. 잠시 후 다시 시도해 주세요.");
return new ResponseEntity<>(response, HttpStatus.SERVICE_UNAVAILABLE);
}
}
대체 경로 제공
서비스가 차단되었을 때 클라이언트가 받게 될 '안전한 응답'을 정의
- 단순한 에러 페이지 대신, "현재 시스템 부하로 인해 요청을 처리할 수 없습니다"와 같은 안내 메시지를 담아 503 Service Unavailable 상태로 반환. 이는 클라이언트 앱이 상황에 맞게 UI를 대응할 수 있도록 함
테스트
@Test
@DisplayName("백엔드_서비스_다운_시_서킷_브레이커가_Fallback_경로로_전달해야_한다")
void 백엔드_서비스_다운_시_서킷_브레이커가_Fallback_경로로_전달해야_한다() {
webClient.get().uri(PROTECTED_SERVICE_URI)
.header("Authorization", "Bearer " + VALID_TOKEN)
.exchange()
.expectStatus().is5xxServerError()
.expectBody()
.jsonPath("$.message").isEqualTo("현재 시스템 부하로 인해 요청을 처리할 수 없습니다. 잠시 후 다시 시도해 주세요.");
}
- 시스템 전체의 연쇄 장애 방지
- 장애가 발생한 서비스로의 요청을 입구(Gateway)에서 즉시 차단
- 특정 서비스가 죽어도 다른 서비스(로그인, 주문 등)는 정상적으로 작동할 수 있는 '장애 격리'가 이루어짐
- 자원 보호 및 빠른 회복 (Fail-Fast)
- 응답이 오지 않는 서비스를 무한정 기다리지 않음
- 서버의 스레드나 메모리가 대기 중인 요청들로 인해 고갈되는 것을 막아, 장애 서비스가 복구되었을 때 시스템이 더 빠르게 정상 상태로 돌아올 수 있음
- 사용자 경험(UX) 유지
- 알 수 없는 에러나 무한 로딩 대신 명확한 안내를 제공
- 사용자는 "시스템 점검 중"임을 인지하고 잠시 후 다시 시도할 수 있으며, 클라이언트 앱은 무한 로딩 스피너에 갇히지 않음.
- 인프라 안정성 향상
- 부하가 걸린 서비스에 계속해서 '재시도 폭탄'을 던지는 것을 방지
- 시적인 과부하 상태에서 서킷 브레이커가 요청을 차단해 주는 동안, 대상 서비스는 스스로 회복할 수 있는 최소한의 시간을 벌 수 있음
feat: Gateway 안정성 확보를 위한 Resilience4j 서킷 브레이커 및 Fallback 구현 by 0hj1hyeon · Pull Request #9 ·
WebFlux 기반 resilience4j를 사용 Fallback 처리: 장애 발생 시 FallbackController로 포워딩 503 상태와 메시지 전달
github.com
'분산 처리 환경' 카테고리의 다른 글
| 스프링 분산 처리 환경 11: Docker (0) | 2025.12.14 |
|---|---|
| 스프링 분산 처리 환경 10: 중간 정리 (0) | 2025.11.23 |
| 스프링 분산 처리 환경 8: Spring Cloud Gateway, JWT 인가 필터 및 경로별 라우팅 검증 테스트 (1) | 2025.11.19 |
| 스프링 분산 처리 환경 7: Spring Cloud Gateway 환경에서 JWT 인증 (1) | 2025.11.17 |
| 스프링 분산 처리 환경 6: Spring Cloud Gateway (0) | 2025.11.15 |