Core modules
Resilience4j는 5개의 Core modules을 제공합니다.
CircuitBreaker
CircuitBreaker 패턴을 구현한 모듈입니다. 호출의 결과를 저장하고 집계(Aggregate)하기 위한 슬라이딩 윈도를 사용합니다.
요청 실패율(Failure rate)이 몇 퍼센트 이상일 때 서킷의 상태가 CLOSED에서 OPEN으로 바뀔지 그리고 요청 중 지연된 응답(Slow calls)이 몇 퍼센트 이상일 때 서킷의 상태가 CLOSED에서 OPEN으로 바뀔지 설정할 수 있습니다.
슬라이딩 윈도우 크기가 15인 경우에도. 슬라이딩 윈도우가 15개의 요청만 동시에 실행할 수 있다는 것을 의미하지는 않습니다. 동시 스레드 수를 제한하려면 벌크헤드를 사용해야한다.(아래에서 다룸)
두 가지 종류의 윈도우 중 하나를 선택하여 사용할 수 있습니다.
1. 마지막 N개의 요청의 결과를 집계하는 카운트 베이스 윈도우(count-based window)
- 설정한 window size N만큼의 값을 가질 수 있는 circular array로 구현
- 새 요청 결과가 기록되면 업데이트되며 가장 오래된 측정값이 제거되면 측정값이 총집계에서 차감되고 버킷 재설정
- 스냅샷은 미리 집계되고 창 크기와 독립적이므로 스냅샷 검색 시간 복잡도는 O(1)
- 공간 요구 사항(메모리 소비량)은 O(n)
2. 마지막 N초 동안 요청의 결과를 집계하는 시간 베이스 윈도우(time-based window)
- N 부분 집합(버킷)의 circular array로 구현
- 모든 버킷은 특정 초(epoch second)에 발생하는 모든 요청의 결과를 집계
- 가장 오래된 버킷이 제거되면 해당 버킷의 총 집계가 총 집계에서 부분적으로 차감되고 버킷 재설정
- 스냅샷은 미리 집계되고 기간 크기와 독립적이므로 스냅샷 검색 시간 복잡도는 O(1)
- 공간 요구 사항(메모리 소비)은 거의 일정한 O(n), N개의 부분집계와 1개의 총집계만 생성
Config | propertyDefault | ValueDescription |
failureRateThreshold | 50 | 실패율(failure ratio) threshold퍼센트 값 실패율 임계값보다 크거나 같으면 CircuitBreaker가 개방으로 전환하고 단락 호출을 시작 |
slowCallRateThreshold | 100 | 지연된 응답(failure ratio) threshold 퍼센트 값 느린 호출의 백분율이 임계값과 같거나 크면 CircuitBreaker가 개방으로 전환되고 단락 호출이 시작 |
slowCallDurationThreshold | 60000 [ms] | 요청이 느린 것으로 간주되는 기간 |
permittedNumberOfCalls InHalfOpenState |
10 | Half-open 상태에서 허가된 요청 수 |
maxWaitDurationInHalfOpenState | 0 | Half-open 상태에서 대기할 수 있는 최대 시간 0은 무한정 기다리는 것을 의미 |
slidingWindowType | COUNT_BASED | CircuitBreaker가 닫혔을 때 호출 결과를 기록하는 데 사용되는 슬라이딩 윈도우의 유형을 구성합니다. COUNT_BASED이면 마지막 슬라이딩 WindowSize 호출이 기록되고 집계 TIME_BASSED이면 마지막 슬라이딩 WindowSize 초의 호출이 기록되고 집계 |
slidingWindowSize | 100 | 서킷의 상태가 CLOSED일 때 요청의 결과를 기록하기 위한 슬라이딩 윈도의 크기 |
minimumNumberOfCalls | 100 | 서킷이 실패율(failure rate) 또는 지연된 응답(slow call rate)을 계산하기 전 요구되는 최소 요청의 수 |
waitDurationInOpenState | 60000 [ms] | 서킷이 OPEN 에서 Half-open으로 변경되기 전 대기하는 시간 (이 시간 이후 변경된다.) |
automaticTransition FromOpenToHalfOpenEnabled |
false | true 라면 waitDurationInOpenState 기간이 지난 이후에 Open에서 Half-open으로 자동으로 상태가 변경된다. 하나의 쓰레드가 CircuitBreaker의 모든 인스턴스들을 모니터링하며 상태를 확인한다. false라면 요청이 있을 때만 상태가 Half-open으로 변경된다. 즉, waitDurationInOpenState 기간이 지난 후에 새로운 요청이 있으면 Half-open 상태로 변경된다.모니터링을 위한 쓰레드가 필요없는 이점이 있다. |
recordExceptions | empty | 실패로 기록될 예외의 리스트로 실패율(failure rate)가 증가되는 예외 리스트이다. 예외 리스트를 설정한다면, 다른 모든 예외는 ignoreExceptions에 의해 무시되지 않는다면 성공으로 간주된다. |
ignoreExceptions | empty | 성공 또는 실패로 기록되지 않는 예외들의 리스트이다. |
recordException | throwable -> true By default all exceptions are recored as failures. |
커스텀 Predicate로 예외가 실패로 기록될지 정의 할 수 있다. 예외가 실패로 카운트 되야 한다면 true를 리턴하고 성공으로 카운트 되야 한다면 false를 리턴해야 한다. (ignoreExceptions에 의해 무시되지 않는 경우) |
ignoreException | throwable -> false By default no exception is ignored. |
커스텀 Predicate로 예외가 무시될지 정의할 수 있다. 예외가 무시되려면 true를 리턴하고 실패로 카운트 되려면 false를 리턴해야 한다. |
// 코드 예시
// Create a custom configuration for a CircuitBreaker
CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()
.failureRateThreshold(50)
.slowCallRateThreshold(50)
.waitDurationInOpenState(Duration.ofMillis(1000))
.slowCallDurationThreshold(Duration.ofSeconds(2))
.permittedNumberOfCallsInHalfOpenState(3)
.minimumNumberOfCalls(10)
.slidingWindowType(SlidingWindowType.TIME_BASED)
.slidingWindowSize(5)
.recordException(e -> INTERNAL_SERVER_ERROR
.equals(getResponse().getStatus()))
.recordExceptions(IOException.class, TimeoutException.class)
.ignoreExceptions(BusinessException.class, OtherBusinessException.class)
.build();
// Create a CircuitBreakerRegistry with a custom global configuration
CircuitBreakerRegistry circuitBreakerRegistry =
CircuitBreakerRegistry.of(circuitBreakerConfig);
// Get or create a CircuitBreaker from the CircuitBreakerRegistry
// with the global default configuration
CircuitBreaker circuitBreakerWithDefaultConfig =
circuitBreakerRegistry.circuitBreaker("name1");
// Get or create a CircuitBreaker from the CircuitBreakerRegistry
// with a custom configuration
CircuitBreaker circuitBreakerWithCustomConfig = circuitBreakerRegistry
.circuitBreaker("name2", circuitBreakerConfig);
# 스프링부트 설정 예시
resilience4j.circuitbreaker:
configs:
default:
registerHealthIndicator: true
slidingWindowSize: 10
minimumNumberOfCalls: 5
permittedNumberOfCallsInHalfOpenState: 3
automaticTransitionFromOpenToHalfOpenEnabled: true
waitDurationInOpenState: 5s
failureRateThreshold: 50
eventConsumerBufferSize: 10
recordExceptions:
- org.springframework.web.client.HttpServerErrorException
- java.util.concurrent.TimeoutException
- java.io.IOException
ignoreExceptions:
- io.github.robwin.exception.BusinessException
shared:
slidingWindowSize: 100
permittedNumberOfCallsInHalfOpenState: 30
waitDurationInOpenState: 1s
failureRateThreshold: 50
eventConsumerBufferSize: 10
ignoreExceptions:
- io.github.robwin.exception.BusinessException
instances:
backendA:
baseConfig: default
Bulkhead
Resilience4j는 동시 실행(Concurrent execution) 수를 제한하는데 사용되는 두개의 bulkhead 패턴 구현체를 제공합니다.
SemaphoreBulkhead는 다양한 스레딩 및 I/O 모델에서 잘 작동
벌크헤드 구성과 일치하는 올바른 스레드 풀 크기를 확인하는 것은 클라이언트에 달려 있습니다.
- Semaphores를 사용하는 SemaphoreBulkhead
- 고정된 Thread pool과 Bounded queue를 사용하는 FixedThreadPoolBulkHead
SemaphoreBulkhead Config
Config | propertyDefault | valueDescription |
maxConcurrentCalls | 25 | Bulkhead에 의해 허가된 동시 실행 최대 수 |
maxWaitDuration | 0 | 포화 상태의 Bulkhead에 진입하기 위해 block 되는 최대 시간 값이 0인 경우에는 바로 요청을 막는다. |
// 코드 예시
// Create a custom configuration for a Bulkhead
BulkheadConfig config = BulkheadConfig.custom()
.maxConcurrentCalls(150)
.maxWaitDuration(Duration.ofMillis(500))
.build();
// Create a BulkheadRegistry with a custom global configuration
BulkheadRegistry registry = BulkheadRegistry.of(config);
// Get or create a Bulkhead from the registry -
// bulkhead will be backed by the default config
Bulkhead bulkheadWithDefaultConfig = registry.bulkhead("name1");
// Get or create a Bulkhead from the registry,
// use a custom configuration when creating the bulkhead
Bulkhead bulkheadWithCustomConfig = registry.bulkhead("name2", custom);
# 스프링부트 설정 예시
resilience4j.bulkhead:
configs:
default:
maxConcurrentCalls: 100
instances:
backendA:
maxConcurrentCalls: 10
backendB:
maxWaitDuration: 10ms
maxConcurrentCalls: 20
FixedThreadPoolBulkHead Config
Config | propertyDefault | valueDescription |
maxThreadPoolSize | Runtime.getRuntime() .availableProcessors() |
최대 쓰레드 풀 크기 |
coreThreadPoolSize | Runtime.getRuntime() .availableProcessors() - 1 |
코어 쓰레드 풀 크기 |
queueCapacity | 100 | 큐의 크기 |
keepAliveDuration | 20 [ms] | 스레드 수가 코어보다 크면 초과된 유휴 스레드가 종료하기 전에 새 작업을 대기하는 최대 시간 |
// 코드 예시
ThreadPoolBulkheadConfig config = ThreadPoolBulkheadConfig.custom()
.maxThreadPoolSize(10)
.coreThreadPoolSize(2)
.queueCapacity(20)
.build();
// Create a BulkheadRegistry with a custom global configuration
ThreadPoolBulkheadRegistry registry = ThreadPoolBulkheadRegistry.of(config);
// Get or create a ThreadPoolBulkhead from the registry -
// bulkhead will be backed by the default config
ThreadPoolBulkhead bulkheadWithDefaultConfig = registry.bulkhead("name1");
// Get or create a Bulkhead from the registry,
// use a custom configuration when creating the bulkhead
ThreadPoolBulkheadConfig custom = BulkheadConfig.custom()
.maxThreadPoolSize(5)
.build();
ThreadPoolBulkhead bulkheadWithCustomConfig = registry.bulkhead("name2", custom);
# 스프링부트 설정 예시
resilience4j.thread-pool-bulkhead:
configs:
default:
maxThreadPoolSize: 4
coreThreadPoolSize: 2
queueCapacity: 2
instances:
backendA:
baseConfig: default
backendB:
maxThreadPoolSize: 1
coreThreadPoolSize: 1
queueCapacity: 1
RateLimiter
일정 시간동안 요청 수를 제한하는데 사용됩니다.
속도 제한은 API의 확장에 대비하고 서비스의 높은 가용성과 안정성을 확립하기 위해 반드시 필요한 기술
제한 초과 요청을 거부하거나 대기열을 작성하여 나중에 실행하거나 이 두 가지 접근 방식을 조합할 수 있습니다.
Config | propertyDefault | valueDescription |
timeoutDuration | 5 [s] | 허가(Permission)을 위해 쓰레드가 대기하는 기본 시간 |
limitRefreshPeriod | 500 [ns] | Limit refresh 기간으로, 각 기간 이후에 RateLimiter가 일정 시간 동안 허가되는 요청 수를 다시 설정한다. |
limitForPeriod | 50 | 한 Limit refresh 기간 동안 허가되는 요청 수 |
// 코드 예시
RateLimiterConfig config = RateLimiterConfig.custom()
.limitRefreshPeriod(Duration.ofMillis(1))
.limitForPeriod(10)
.timeoutDuration(Duration.ofMillis(25))
.build();
// Create registry
RateLimiterRegistry rateLimiterRegistry = RateLimiterRegistry.of(config);
// Use registry
RateLimiter rateLimiterWithDefaultConfig = rateLimiterRegistry
.rateLimiter("name1");
RateLimiter rateLimiterWithCustomConfig = rateLimiterRegistry
.rateLimiter("name2", config);
# 스프링부트 설정 예시
resilience4j.ratelimiter:
configs:
default:
registerHealthIndicator: false
limitForPeriod: 10
limitRefreshPeriod: 1s
timeoutDuration: 0
eventConsumerBufferSize: 100
instances:
backendA:
baseConfig: default
backendB:
limitForPeriod: 6
limitRefreshPeriod: 500ms
timeoutDuration: 3s
Retry
요청이 실패했을 경우 재시도 정책에 관련한 조건을 관리하기 위해 사용됩니다.
Config | propertyDefault | valueDescription |
maxAttempts | 3 | 최대 재시도 수 |
waitDuration | 500 [ms] | 재시도 사이에 고정된 대기 시간 |
intervalFunction | numOfAttempts -> waitDuration | 요청 실패 이후 대기 간격을 수정하기 위한 함수이다. 기본적으로는 대기 시간(waitDuration)이 일정하게 유지된다. |
retryOnResultPredicate | result -> false | 결과에 따라 재시도 여부를 결정하기 위한 Predicate를 설정한다. 만약 결과가 재시도 되야 한다면, true를 리턴해야하고 그렇지 않다면 false를 리턴해야 한다. |
retryOnExceptionPredicate | throwable -> true | 예외(Exception)에 따라 재시도 여부를를 결정하기 위한 Predicate를 설정한다. 만약 예외에 따라 재시도 되야 한다면, true를 리턴해야하고 그렇지 않다면 false를 리턴해야 한다. |
retryExceptions | empty | 실패로 기록되는 에러 클래스 리스트 즉, 재시도 되야하는 에러 클래스의 리스트이다. empty일 경우 모든 에러 클래스를 재시도 한다. |
ignoreExceptions | empty | 무시되야 하는 에러 클래스 리스트 즉, 재시도 되지 않아야 할 에러 클래스 리스트이다. |
// 코드 예시
RetryConfig config = RetryConfig.custom()
.maxAttempts(2)
.waitDuration(Duration.ofMillis(1000))
.retryOnResult(response -> response.getStatus() == 500)
.retryOnException(e -> e instanceof WebServiceException)
.retryExceptions(IOException.class, TimeoutException.class)
.ignoreExceptions(BusinessException.class, OtherBusinessException.class)
.failAfterMaxAttempts(true)
.build();
// Create a RetryRegistry with a custom global configuration
RetryRegistry registry = RetryRegistry.of(config);
// Get or create a Retry from the registry -
// Retry will be backed by the default config
Retry retryWithDefaultConfig = registry.retry("name1");
// Get or create a Retry from the registry,
// use a custom configuration when creating the retry
RetryConfig custom = RetryConfig.custom()
.waitDuration(Duration.ofMillis(100))
.build();
Retry retryWithCustomConfig = registry.retry("name2", custom);
# 스프링부트 설정 예시
resilience4j.retry:
configs:
default:
maxAttempts: 3
waitDuration: 100
retryExceptions:
- org.springframework.web.client.HttpServerErrorException
- java.util.concurrent.TimeoutException
- java.io.IOException
ignoreExceptions:
- io.github.robwin.exception.BusinessException
instances:
backendA:
baseConfig: default
backendB:
baseConfig: default
TimeLimiter
원격 서버를 호출하는데 걸리는 시간을 제한할 수 있습니다.
Config | propertyDefault | valueDescription |
timeoutDuration | 1 [s] | Timeout 값 (기본 단위는 ms) |
cancelRunningFuture | true | Timeout 발생 후 future를 취소할지 결정하는 Boolean 값 |
// 코드 예시
TimeLimiterConfig config = TimeLimiterConfig.custom()
.cancelRunningFuture(true)
.timeoutDuration(Duration.ofMillis(500))
.build();
// Create a TimeLimiterRegistry with a custom global configuration
TimeLimiterRegistry timeLimiterRegistry = TimeLimiterRegistry.of(config);
// Get or create a TimeLimiter from the registry -
// TimeLimiter will be backed by the default config
TimeLimiter timeLimiterWithDefaultConfig = registry.timeLimiter("name1");
// Get or create a TimeLimiter from the registry,
// use a custom configuration when creating the TimeLimiter
TimeLimiterConfig config = TimeLimiterConfig.custom()
.cancelRunningFuture(false)
.timeoutDuration(Duration.ofMillis(1000))
.build();
TimeLimiter timeLimiterWithCustomConfig = registry.timeLimiter("name2", config);
# 스프링부트 설정 예시
resilience4j.timelimiter:
configs:
default:
cancelRunningFuture: false
timeoutDuration: 2s
instances:
backendA:
baseConfig: default
backendB:
baseConfig: default
Reference
https://github.com/resilience4j/resilience4j-spring-boot2-demo
'Spring Cloud' 카테고리의 다른 글
6. Spring Cloud Config (0) | 2021.06.20 |
---|---|
5. zuul - [Spring Cloud를 활용한 MSA 기초 온라인 강의 실습] (0) | 2021.06.18 |
4. Feign - [Spring Cloud를 활용한 MSA 기초 온라인 강의 실습] (0) | 2021.06.17 |
3. Eureka - [Spring Cloud를 활용한 MSA 기초 온라인 강의 실습] (0) | 2021.06.16 |
2. Ribbon - [Spring Cloud를 활용한 MSA 기초 온라인 강의 실습] (0) | 2021.06.15 |