본문 바로가기

Spring

서비스 장애로부터 안전망을 구축하라! Spring Boot에서 Resilience4j로 Circuit Breaker 구현하기

728x90
반응형

1. Circuit Breaker란 무엇인가?

Circuit Breaker(회로 차단기)는 마이크로서비스 아키텍처에서 자주 사용되는 패턴 중 하나로, 장애가 발생한 서비스를 호출할 때 시스템 전체로 장애가 확산되는 것을 방지하는 역할을 합니다. 서비스 간의 호출에서 장애가 발생할 수 있는 여러 상황(서버 다운, 응답 지연 등)을 예상하여, 시스템이 과부하에 걸리지 않도록 호출을 중단하고, 일정 시간 후 재시도를 통해 서비스의 정상화를 감지합니다.

Circuit Breaker는 주로 다음과 같은 세 가지 상태로 동작합니다:

  • Closed (닫힘): 모든 요청이 정상적으로 처리됩니다. 서비스가 정상적이라고 판단되며, 호출 시도는 계속됩니다.
  • Open (열림): 일정 횟수 이상의 실패가 발생하면 Circuit Breaker가 열리고, 해당 서비스로의 모든 호출이 차단됩니다. 이 상태에서는 서비스 복구가 확인되기 전까지 호출을 멈춥니다.
  • Half-Open (반열림): 일정 시간이 지난 후 제한된 수의 호출을 허용합니다. 이 호출이 성공하면 Circuit Breaker는 다시 Closed 상태로 전환됩니다. 실패하면 Open 상태로 되돌아갑니다.

이러한 패턴을 통해 불필요한 재시도 및 과부하를 막고, 전체 시스템의 안정성을 높일 수 있습니다.


2. Resilience4j란?

Resilience4j는 회복성(resilience) 패턴을 구현하기 위한 경량의 라이브러리로, 특히 Java에서 Circuit Breaker, Rate Limiter, Retry, Bulkhead와 같은 패턴을 제공하는데 최적화되어 있습니다. Spring Boot와 쉽게 통합할 수 있으며, 비동기/동기 방식 모두를 지원하고, Spring Boot의 어노테이션을 활용한 손쉬운 설정을 제공합니다.

Resilience4j는 Java 8 함수형 인터페이스와 통합되어 있어 매우 유연하며, Spring Cloud Netflix의 Hystrix가 더 이상 유지보수되지 않는 상황에서 Hystrix를 대체하는 훌륭한 선택지로 자리 잡고 있습니다.

Resilience4j의 주요 컴포넌트:

  • Circuit Breaker: 서비스 호출 실패를 감지하고 자동으로 보호.
  • Retry: 서비스가 실패하면 자동으로 재시도.
  • Rate Limiter: 특정 시간 동안 호출할 수 있는 횟수를 제한.
  • Bulkhead: 병렬로 실행되는 작업의 최대 수를 제한하여 시스템 보호.
  • Time Limiter: 서비스 호출이 일정 시간 안에 완료되지 않으면 타임아웃 처리.
반응형

3. Resilience4j로 Circuit Breaker 구현 예제 (Gradle 프로젝트)

이제 Resilience4j Circuit Breaker를 Spring Boot 프로젝트에서 어떻게 구현할 수 있는지 살펴보겠습니다.

프로젝트 설정1) Gradle 의존성 추가

먼저, 프로젝트에 resilience4j-circuitbreaker 의존성을 추가합니다.

build.gradle

plugins {
    id 'org.springframework.boot' version '3.1.0'
    id 'io.spring.dependency-management' version '1.1.0'
    id 'java'
}

group = 'com.example'
version = '1.0.0'
sourceCompatibility = '17'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'io.github.resilience4j:resilience4j-spring-boot3:2.0.2'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

test {
    useJUnitPlatform()
}

resilience4j-spring-boot3 의존성을 통해 Circuit Breaker를 쉽게 설정할 수 있습니다.

2) Circuit Breaker 설정

이제 Circuit Breaker 설정을 application.yml 파일에 추가합니다. Circuit Breaker의 기본 동작 조건을 설정할 수 있으며, 여기서는 실패 횟수가 5번을 넘으면 Circuit Breaker가 Open 상태로 전환되도록 설정하겠습니다.

application.yml

resilience4j.circuitbreaker:
  instances:
    backendA:
      registerHealthIndicator: true
      slidingWindowSize: 10
      failureRateThreshold: 50
      waitDurationInOpenState: 10000 # Open 상태로 유지될 시간 (밀리초)
      permittedNumberOfCallsInHalfOpenState: 3
      slidingWindowType: COUNT_BASED
      minimumNumberOfCalls: 5
      automaticTransitionFromOpenToHalfOpenEnabled: true

위 설정은 backendA라는 이름의 Circuit Breaker 인스턴스를 생성하며, 다음과 같은 동작을 정의합니다:

  • failureRateThreshold: 실패율이 50%를 넘으면 Circuit Breaker가 Open 상태로 전환.
  • slidingWindowSize: 10개의 호출을 기준으로 상태를 평가.
  • waitDurationInOpenState: Circuit Breaker가 Open 상태일 때 10초 동안 유지.
  • permittedNumberOfCallsInHalfOpenState: Half-Open 상태에서 허용할 호출 수.

3) Service 클래스 구현

다음으로, 외부 API를 호출하는 간단한 서비스 클래스를 구현하고, 여기에 Circuit Breaker를 적용하겠습니다.

ExternalService.java

package com.example.circuitbreaker;

import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class ExternalService {

    private final RestTemplate restTemplate;

    public ExternalService(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    public String callExternalApi() {
        // 외부 API를 호출하는 메서드 (예: https://jsonplaceholder.typicode.com/posts/1)
        String url = "https://jsonplaceholder.typicode.com/posts/1";
        return restTemplate.getForObject(url, String.class);
    }
}

이 서비스는 외부 API를 호출하는 역할을 합니다.

4) Circuit Breaker 적용

이제 Resilience4j의 Circuit Breaker를 적용한 메서드를 컨트롤러에서 호출하도록 설정해보겠습니다. Spring Boot에서는 @CircuitBreaker 어노테이션을 통해 쉽게 Circuit Breaker를 적용할 수 있습니다.

ExternalController.java

package com.example.circuitbreaker;

import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ExternalController {

    private final ExternalService externalService;

    public ExternalController(ExternalService externalService) {
        this.externalService = externalService;
    }

    @GetMapping("/external")
    @CircuitBreaker(name = "backendA", fallbackMethod = "fallback")
    public String callExternal() {
        return externalService.callExternalApi();
    }

    public String fallback(Exception e) {
        return "외부 서비스가 현재 사용 불가합니다. 잠시 후 다시 시도해주세요.";
    }
}
  • @CircuitBreaker 어노테이션을 통해 backendA라는 이름의 Circuit Breaker를 적용합니다.
  • fallbackMethod 속성은 서비스가 실패했을 때 호출할 대체 메서드를 지정합니다. 여기서는 fallback 메서드가 호출됩니다.

5) RestTemplate 빈 설정

RestTemplate을 사용하기 위해 Bean을 등록해야 합니다.

RestTemplateConfig.java

package com.example.circuitbreaker;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

이제 /external 경로로 요청을 보내면 외부 API를 호출하게 되고, 실패 시 Circuit Breaker가 작동하여 fallback 메서드가 호출됩니다.


4. 구현 시 주의 사항

  1. 적절한 임계치 설정: Circuit Breaker는 서비스 상태를 평가하는 기준이 되는 슬라이딩 윈도우 크기실패율을 적절히 설정해야 합니다. 너무 낮은 임계치로 설정하면 불필요하게 Circuit Breaker가 자주 작동할 수 있으며, 너무 높게 설정하면 장애 감지가 늦어질 수 있습니다.
  2. Fallback 처리: 장애 발생 시 대체 동작(fallback)이 반드시 필요합니다. 이를 통해 사용자에게 명확한 응답을 제공하고 시스템이 불필요한 부하를 받지 않도록 보호합니다.
  3. 로그 및 모니터링: Circuit Breaker가 언제, 얼마나 자주 동작하는지 모니터링하는 것이 중요합니다. Resilience4j는 메트릭을 제공하므로 이를 Prometheus, Grafana 등과 연동하여 모니터링 시스템을 구축할 수 있습니다.
  4. Circuit Breaker 상태 관리: Open 상태로 전환되면 일정 시간 동안 모든 호출이 차단되므로, 이 상태를 적절하게 관리해야 시스템의 가용성을 높일 수 있습니다.

728x90

Circuit Breaker는 서비스 장애로부터 시스템을 보호하고, Resilience4j는 이를 효율적으로 구현할 수 있는 강력한 라이브러리입니다. Spring Boot와 Resilience4j를 통해 Circuit Breaker 패턴을 간단하게 적용하여, 장애를 효과적으로 관리하고 시스템을 안정적으로 유지할 수 있습니다.

728x90
반응형