Spring Boot · 2026-02-06

Resilience4j로 Spring Boot 회로 차단기 적용

Resilience4j를 통해 Spring Boot에서 회로 차단기, 재시도, 시간 제한, 장애 격리를 설정하는 방법과 예제 코드·구성 정보를 정리한 기술설명

작성일 : 2026-02-06 ㆍ 작성자 : 관리자
post
목차

소개

마이크로서비스 환경에서는 외부 서비스 장애가 전체 시스템에 전파될 수 있다. Resilience4j는 경량 라이브러리로 회로 차단기(circuit breaker), 재시도(retry), 시간 제한(time limiter), 장애 격리(bulkhead) 같은 패턴을 제공한다. 이 글은 처음 접하는 개발자도 이해할 수 있도록 구성과 예제를 중심으로 설명한다.

핵심 개념

회로 차단기 (Circuit Breaker)

특정 서비스 호출 실패율이 일정 임계치에 도달하면 호출을 차단하고 빠르게 실패로 응답한다. 복구 시에는 일부 요청만 허용해 상태를 확인한다.

재시도 (Retry)

일시적 실패에 대해 지정된 횟수만큼 재시도한다. 과도한 재시도는 역효과를 낼 수 있으므로 백오프(backoff) 전략 병행이 권장된다.

시간 제한 (TimeLimiter)과 장애 격리 (Bulkhead)

응답 지연이 길어질 경우 비동기로 처리해 타임아웃을 설정한다. 동시에 처리 가능한 동시성 수를 제한해 서비스 간 영향을 줄이는 것이 장애 격리다.

설치 및 설정

Spring Boot 프로젝트에 Resilience4j 의존성을 추가하고 application.yml로 정책을 정의한다.

Gradle 의존성 예

plugins {
    id 'org.springframework.boot' version '2.7.0'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'java'
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'io.github.resilience4j:resilience4j-spring-boot2'
    implementation 'io.github.resilience4j:resilience4j-retry'
    implementation 'org.springframework.boot:spring-boot-starter-aop'
}

application.yml 예

resilience4j:
  circuitbreaker:
    instances:
      backendService:
        registerHealthIndicator: true
        slidingWindowType: COUNT_BASED
        slidingWindowSize: 20
        minimumNumberOfCalls: 5
        permittedNumberOfCallsInHalfOpenState: 3
        failureRateThreshold: 50
        waitDurationInOpenState: 10s
  retry:
    instances:
      backendService:
        maxRetryAttempts: 3
        waitDuration: 500ms
  timelimiter:
    instances:
      backendService:
        timeoutDuration: 2s
  bulkhead:
    instances:
      backendService:
        maxConcurrentCalls: 10
        maxWaitDuration: 0ms
management:
  endpoints:
    web:
      exposure:
        include: health,metrics,prometheus

실전 코드 예제

다음은 서비스 레이어에 Resilience4j 애노테이션을 적용한 예제다. 회로 차단기와 재시도, 시간 제한을 함께 사용하는 패턴을 보여준다.

Service 구현

package com.example.service;

import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import io.github.resilience4j.retry.annotation.Retry;
import io.github.resilience4j.timelimiter.annotation.TimeLimiter;
import java.util.concurrent.CompletableFuture;
import org.springframework.stereotype.Service;

@Service
public class BackendService {

    @CircuitBreaker(name = "backendService", fallbackMethod = "fallback")
    @Retry(name = "backendService")
    public String callExternalApi() {
        // 외부 HTTP 호출 로직
        // 예: RestTemplate나 WebClient 사용
        throw new RuntimeException("external failure");
    }

    public String fallback(Throwable t) {
        return "fallback response";
    }

    @CircuitBreaker(name = "backendService", fallbackMethod = "fallbackAsync")
    @TimeLimiter(name = "backendService")
    public CompletableFuture<String> callExternalApiAsync() {
        return CompletableFuture.supplyAsync(() -> {
            // 지연이 있는 작업
            return "ok";
        });
    }

    public CompletableFuture<String> fallbackAsync(Throwable t) {
        return CompletableFuture.completedFuture("fallback async");
    }
}

Controller 예

package com.example.controller;

import com.example.service.BackendService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ApiController {

    private final BackendService backendService;

    public ApiController(BackendService backendService) {
        this.backendService = backendService;
    }

    @GetMapping("/sync")
    public ResponseEntity<String> sync() {
        return ResponseEntity.ok(backendService.callExternalApi());
    }

    @GetMapping("/async")
    public CompletableFuture<ResponseEntity<String>> async() {
        return backendService.callExternalApiAsync().thenApply(ResponseEntity::ok);
    }
}

적용 흐름과 주의사항

  • 정책은 서비스 성격에 맞게 튜닝한다. 실패율 임계치와 슬라이딩 윈도 크기는 트래픽 패턴에 따라 조정한다.
  • 재시도는 멱등성이 보장되는 호출에서만 사용한다. 상태 변경 요청에는 주의가 필요하다.
  • TimeLimiter는 블로킹 호출을 비동기화하여 적용한다. CompletableFuture 반환을 사용한다.
  • Bulkhead로 동시성 제한을 걸면 자원 고갈을 예방할 수 있다. 동시성 설정은 서비스 용량을 고려한다.

모니터링과 테스트

Spring Actuator와 Micrometer를 함께 사용하면 회로 차단기 상태와 메트릭을 수집할 수 있다. Prometheus와 Grafana로 대시보드를 구성하면 이상 징후를 조기에 발견하기 쉽다.

마무리

Resilience4j는 경량이면서도 핵심적인 회복탄력성 패턴을 제공한다. 설정과 코드 예제를 통해 회로 차단기, 재시도, 시간 제한, 장애 격리를 함께 적용하면 외부 장애로부터 내부 서비스를 보호하는 데 큰 도움이 된다. 실제 운영 환경에서는 메트릭 기반 튜닝과 재시도 정책의 신중한 적용이 중요하다.

resilience4j spring boot 사용법 spring boot circuit breaker resilience4j resilience4j retry 예제 Resilience4j circuit breaker retry time limiter bulkhead