회복탄력성(Resilience)은 시스템이 예상치 못한 장애나 오류 발생 시에도 정상적으로 동작할 수 있는 능력을 의미합니다.
resilience4j - retry 기능
재시도는 특정 요청이 실패했을때 바로 실패했다고 간주하는것이 아니라 몇 번 더 시도해보는것을 의미합니다.
일반적으로 일시적인 오류로부터 시스템을 보호하기 위해 사용됩니다. 예를 들어 네트워크 연결이 불안정할 때나 외부 서비스가 일시적으로 응답하지 않을 때 등에 유용합니다.
- Retry Policy (재시도 정책): Retry 동작을 정의하는 정책입니다. 이 정책은 재시도를 언제 해야 하는지, 얼마나 자주 해야 하는지, 얼마나 많이 해야 하는지 등을 결정합니다.
- Stop Strategies (중단 전략): 재시도를 멈추는 전략을 정의합니다. 예를 들어 최대 재시도 횟수를 설정하거나, 특정 조건을 만족할 때 중단시키는 등의 전략을 사용할 수 있습니다.
- Wait Strategies (대기 전략): 재시도 간의 대기 시간을 정의합니다. 일정 시간 동안 대기하거나, 지수적으로 대기하는 등의 전략을 사용할 수 있습니다.
- Retry Events (재시도 이벤트): Retry 동작과 관련된 이벤트를 처리하는 기능을 제공합니다. 예를 들어 재시도가 성공했을 때, 실패했을 때 등의 이벤트를 처리할 수 있습니다.
- Retry Context (재시도 컨텍스트): Retry 동작 중에 현재 재시도 상태에 대한 정보를 추적하고 관리하는 데 사용됩니다.
https://resilience4j.readme.io/
resilience4j
resilience4j.readme.io
SpringBoot build.gradle 의존 설정
implementation 'org.springframework.boot:spring-boot-starter-actuator:3.1.5' // 관제 기능의 actuator
implementation 'io.github.resilience4j:resilience4j-spring-boot3:2.1.0'
implementation 'org.springframework.boot:spring-boot-starter-aop:3.1.5'
implementation 'io.github.resilience4j:resilience4j-all:2.1.0'
Application.yml 설정 (Resilience4j 설정)
resilience4j:
retry:
configs:
default:
max-attempts: 5 # 최대 시도를 몇 번으로 할 것인지
wait-duration: 1000 #최대 대기 시간은 몇 초인가(1초)
retryExceptions:
- com.example.resil.exception.RetryException # RetryExceetion 재시동 대상 예외
ignoreExceptions:
- com.example.resil.excpetion.IgnoreExcpetion # IgnoreExcention 재시동 제외 예외
Retry 애노테이션과 fallbackMethod 설정
- @Retry 애노테이션이 붙은 메서드가 재시도 로직
- 재시도를 구체적으로 어덯게 할지는 CONFIG_CLASS_NAME있 적힌 Config 클래스로 등록된 빈을 통해 설정
- fallback메서드에 적은 메서드가 바로 재시도를 했는데도 문제가 되면 호출해줄 메서드의 시그니처 등록
private static final String CONFIG_CLASS_NAME = "retryConfig";
@Retry(name = CONFIG_CLASS_NAME, fallbackMethod = "fallback")
public String process(String param){
return callAnotherServer(param);
private String callAnotherServer(String param){
// retry exsention retry 된다
throw new RuntimeException("예외 발생 !!! ");
private String fallback(String param, Exception e){
// retry 지정한 실패 횟수를 모두 채우면 fallback있 호출됨
System.out.println(param + "요청을 처리하려고 했지만 실패 한도까지 실패했습니다.");
return "처리됨 : " + e.toString( );
circuit breaker
Circuit Breaker 패턴은 일시적으로 실패한 서비스에 대한 요청을 차단하여 시스템 전체의 부하를 줄이고, 더 많은 오류가 발생하지 않도록 하는 기능을 제공합니다.
- 실패 임계값 설정: 몇 번의 연속 실패가 일어나야 Circuit Breaker가 Open 상태로 전환될지 설정할 수 있습니다.
- 차단 시간 설정: Circuit Breaker가 Open 상태로 유지될 시간을 정의합니다. 이 동안 호출은 차단됩니다.
- 반열림 시간 설정: Half-Open 상태에서 얼마나 많은 호출을 허용할지를 설정합니다.
- 리스너 등록: Circuit Breaker의 상태 변경에 대한 리스너를 등록할 수 있습니다.
- Closed (닫힘) 상태:
- 초기 상태로 서비스 호출이 정상적으로 이루어집니다.
- Circuit Breaker가 호출을 모니터링하고, 호출이 실패하면 실패 횟수를 측정합니다.
- 정해진 실패 임계값을 초과하면 Circuit Breaker는 Open 상태로 전환됩니다.
- sliding window ( tmf 슬라이딩 윈도우는 최근 X개의 요청을 분석해서 open 상태로 바꿀지 말지를 결정합니다.
- Open (열림) 상태:
- 일정 시간 동안 모든 호출이 차단됩니다.
- 이 상태에서 Circuit Breaker는 호출을 통과하지 않고, 대신 빠르게 실패를 반환합니다.
- 일정 시간이 지나면 Circuit Breaker는 Half-Open 상태로 전환됩니다.
- Half-Open (반열림) 상태:
- 일정 시간 동안 제한된 수의 호출만을 허용합니다.
- 이 시간 동안 호출이 성공하면 Circuit Breaker는 Closed 상태로 전환됩니다. 실패하면 다시 Open 상태로 전환됩니다.
Application.yml 설정
resilience4j:
circuitbreaker:
instances:
myCircuitBreaker:
sliding-window-type: COUNT_BASED # "COUNT_BASED" (횟수 기준) 또는 "TIME_BASED" (시간 기준) 선택
minimum-number-of-calls: 2 # 최소 2번 이상 요청이 발생해야 실패율을 계산
slidingWindowSize: 10 # 최근 10개의 요청을 기준으로 실패율 계산
failureRateThreshold: 50 # 실패율이 50%를 넘으면 서킷이 열림
permittedNumberOfCallsInHalfOpenState: 10 # Half-Open 상태에서 10개의 요청 허용 후 결정
waitDurationInOpenState: 5000ms # Open 상태에서 5초 대기 후 Half-Open으로 변경
@CircuitBreaker 애노테이션과 fallbackMethod
- citcuit breaker의 fallback은 retry와 다르게 IgnoreException에 의해서도 실행됩니다. 즉 회로 차단 유발은 안 되지만 메소드는 진행됩니다.
- 즉, IgnoreException에 등록된 유형의 예외를 통해서는 open 상태로의 전환은 이뤄지지 않습니다.
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import org.springframework.stereotype.Service;
@Service
public class FeignService {
private static final String CIRCUITBREAKER_CONFIG = "myCircuitBreaker";
@CircuitBreaker(name = CIRCUITBREAKER_CONFIG, fallbackMethod = "fallback")
public String process(String param) {
return callFeignClient(param);
}
private String fallback(String param, Exception e) {
System.out.println(param + " 파라미터가 예외를 유발했습니다. 예외 메시지: " + e.getMessage());
return "Fallback value for " + param;
}
private String callFeignClient(String param) {
if ("a".equals(param)) {
throw new RuntimeException("A 유형 예외 발생");
} else if ("b".equals(param)) {
throw new IgnoreException("B 유형 예외 발생");
}
return param;
}
}
'SpringBoot' 카테고리의 다른 글
Mockito의 엄격 모드(Strict Stubbing) (0) | 2025.04.11 |
---|---|
spring actuator를 활용한 회복탄력성 관리(2) (0) | 2025.03.25 |
카프카를 활용한 메세지 큐 (0) | 2024.04.02 |
artillery 스트레스 테스트 (0) | 2024.02.29 |
스프링 시큐리티 5.X에서 6버전으로 변경 (0) | 2023.12.31 |