본문 바로가기

Spring

[Spring Cloud] Resilience4j 를 이용한 circuitbreaker 기능 구현

Circuitbreaker란

circuitbreaker란 전기 회로의 회로 차단기에서 차용한 개념이며 주식 용어에서도 사용이 된다.

평상시에는 전기가 흐르거나 거래를 자유롭게할 수 있지만(close state) 급격한 이상 현상이 발생했을 때 회로를 차단 또는 주식 시장의 거래를 정지하여(open state) 각각 회로 보호와 시장의 안정을 위한 장치이다.

여기서 close state가 정상적인 상태이고 open state가 차단상태인지 헷갈릴 수 있는데 이는 전기회로에서 스위치의 개념을 이해해야한다.

 

왼쪽 회로와 같이 스위치가 닫혀있어야지 전류가 흐르고 회로가 정상 작동하게 되고 오른쪽과 같이 스위치가 열려있으면 전류는 흐리지 못하고 회로는 차단이 된다.

micro service 에서도 이와 같은 개념으로 사용되는데 지정된 circuitbreaker의 open state로 전환될 조건이 충족되면 service간의 요청을 차단해 장애 전파를 차단할 수 있다.

여기서 open state의 전환 조건이란 대표적으로 일정 횟수에 대한 실패 확률이라고 볼 수 있다.

circuitbreaker 사용의 이점

  • 장애 전파 차단
  • 요청에 대한 응답까지 기다리는 리소스 낭비 예방

 

Circuitbreaker 의 상태 및 계폐 기준

circuitbreaker의 상태는 open, close, half-open 세가지가 있다.

  • close 상태는 정상적으로 동작하는 회로가 닫힌 상태이다.
  • open 상태는 요청에 특정 문제가 발생하여 설정한 기준에 충족할 때 까지 요청을 멈춘다.
  • half-open 상태는 open 상태에서 특정 기준이 충족되면 전환되는 상태로 설정된 기준이 충족되면 close 상태로 전환된다.

circuitbreaker 의 계폐 기준은 time-based, count-based 두가지가 있다.

  • time-based는 요청이 지정한 기준 시간을 초과할 경우 실패로 계산하여 실패율에 따라 회로 상태를 전환한다.
  • count-based는 요청의 실패한 횟수를 기준으로 실패율을 계산하여 회로 상태를 전환한다.

 

Spring Cloud 에서 Circuitbreaker 구현

의존성 추가

implementation("org.springframework.cloud:spring-cloud-starter-circuitbreaker-resilience4j")

 

circuitbreaker configuration 생성

@Configuration
class Resilience4JConfig {

    @Bean
    fun globalCustomConfiguration(): Customizer<Resilience4JCircuitBreakerFactory> {
        val circuitBreakerConfig = CircuitBreakerConfig.custom()
            .slidingWindowType(COUNT_BASED)
            .slowCallRateThreshold(80f)
            .slowCallDurationThreshold(Duration.ofMillis(2000))
            .failureRateThreshold(80f)
            .minimumNumberOfCalls(100)
            .slidingWindowSize(100)
            .permittedNumberOfCallsInHalfOpenState(100)
            .maxWaitDurationInHalfOpenState(Duration.ofMillis(1000))
            .waitDurationInOpenState(Duration.ofMillis(1000))
            .automaticTransitionFromOpenToHalfOpenEnabled(false)
            .ignoreExceptions(NotFoundException::class.java)
            .build()

        val timeLimiterConfig = TimeLimiterConfig.custom()
            .timeoutDuration(Duration.ofSeconds(3))
            .build()

        return Customizer { factory: Resilience4JCircuitBreakerFactory ->
            factory.configureDefault { id: String? ->
                Resilience4JConfigBuilder(id)
                    .timeLimiterConfig(timeLimiterConfig)
                    .circuitBreakerConfig(circuitBreakerConfig)
                    .build()
            }
        }
    }
}

circuitbreaker 설정 종류

  • slidingWindowType(type) - 회로 계폐 기준선택으로 TIME_BASED, COUNT_BASED 두가지 방식이 있다.
  • slowCallRateThreshold(r) -slow call 이 요청의 비율이 r% 이상 되면 회로 차단(open state)
  • slowCallDutationThreshold(t) - 요청의 응답 시간이 t이상 일 시 slow call 로 계산
  • failureRateThreshold(r) - 요청 실패 비율이 r% 이상이 되면 회로는 차단(open state)
  • minimumNumberOfCalls(n) - 요청의 실패와 slow call 의 비율을 계산할 최소 요청 수 지정 (>slidingWindowSize)
  • slidingWindowSize(n) - 회로가 닫혀있을 때 기록할 슬라이딩 윈도우 개수
  • permittedNumberOfCallsInHalfOpenState(n) - 회로가 반-개방 상태일 때 받아들일 요청의 개수
  • maxWaitDurationInHalfOpenState(t) - 회로가 반-개방 상태일 때 열림 상태가 되기까지 대기시간
  • waitDurationInOpenState(t) - 열린 상태로 t 만큼 유지 후 반-개방상태로 전환
  • automaticTransitionFromOpenToHalfOpenEnabled(bool) - 열림 상태에서 반-개방상태로 자동 전환 여부 지정, false 지정 시 waitDurationInOpenState 지정 시간 경과 후 최초 요청이 있을 때 반-개방 상태로 전환된다.
  • ignoreExceptions - 지정된 모든 exception을 성공, 실패 모두 무시한다.
  • recordExceptions - 지정된 모든 exception에 대해 실패로 간주, 외 모든 exception은 성공으로 간주한다.

 

circuitbreaker 사용

circuitBreaker.run({
	// 요청
}, { e ->
    if (e::class.java == CallNotPermittedException::class.java) {
	    // circuit breaker 열림 상태 접근
    }
})