일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- Redis
- 프로그래머스
- EC2
- querydls
- JWT
- trouble shooting
- JPA
- Kafka
- 아키텍처
- MSA
- springboot
- 멀티 모듈
- 테스트 코드
- Til
- docker
- swagger
- Java
- Github Actions
- 유효성 검사
- spring boot
- 객체지향원칙
- DevOps
- 어노테이션
- algorithm
- testcode
- Intellij
- AWS
- rabbitmq
- CI/CD
- aop
- Today
- Total
개발노트
25.02.11 CircuitBreaker 란? 본문
CircuitBreaker
해석하면 누전 차단기 라는 뜻이다.
코드의 흐름을 회로라고 생각하고 과부하가 걸리거나 단락으로 인한 피해를 막기 위해 자동으로 회로를 정지 시키는 장치
라고 정의되어있다한다.
서버에서 사용하면 외부 시스템이나 서비스와의 통시 중에 장애가 발생했을 때 시스템 전체로 장애가 전파되는것을 방지하는 메커니즘이다. 키 포인트는 차단 인 것 같다.
상태
3가지의 보통 상태(OPEN , CLOSED, HALF_OPEN)와 특별한 상태(DISABLED, FORCED_OPEN)를 가지고있다.
보통 상태 3가지에 대해서만 정리해보겠다.
- CLOSED (정상상태)
- 정상적으로 동작하는 상태
- 요청이 서비스로 전달되고 응답을 기다린다.
- 실패율이 설정한 임계치보다 낮으면 현 상태를 유지함
- 평상 시의 호출되고 응답을 받는 기본상태를 보통은 OPEN이라 생각하겠지만 서킷브레이커에서는 CLOSED 임을 기억해야겠다.
- OPEN (에러 상태)
- 서비스 호출 실패가 일정 임계치를 넘으면 회로를 열어 외부 서비스 호출을 완전히 차단한다.
- 설정한 일정 시간 동안 요청이 차단되며, 실패가 다른 서비스로 영향을 미치지 않도록 방지한다.
- OPEN 된 서비스의 클라이언트는 즉각 실패 응답 또는 fallback 메서드의 응답을 받는다.
- 일정시간이 지나면 HALF-OPEN 상태로 전환된다.
- HALF-OPEN (테스트상태)
- 일부 요청을 허용하여 서비스가 복구 되었는지 확인한다.
- 설정한 수의 요청만 허용하고 성공 여부를 기준으로 상태를 다시 CLOSED로 전환한다.
- 실패하면 다시 OPEN 상태로 돌아간다.
- 장애가 해결되었는지 테스트하는 용도이다.
- FallBack
- 시스템에서 장애가 발생했을 때 대체 로직을 실행하는 것이다.
- 주어진 작업이 실패했을 때 대체 경로를 통해 안정성을 유지하고 사용자가 서비스를 이용할 때 흐름이 자연스럽게하는 것 사(사용자 경험 개선)
- 실패한 작업에 대해 로그를 남기거나 알림을 보내는데 유용하다고한다.
// CircuitBreaker 어노테이션을 사용하여 서킷 브레이커 패턴 적용
// - name: 해당 서킷 브레이커를 식별하기 위한 이름 (application.yml에서 설정)
// - fallbackMethod: 메서드 호출 실패 시 대체로 실행될 Fallback 메서드 지정
@CircuitBreaker(name = "productService", fallbackMethod = "fallbackGetProductDetails")
@CircuitBreaker(name = "productService", fallbackMethod = "fallbackGetProductDetails")
public Product getProductDetails(String productId) {
log.info("###Fetching product details for productId: {}", productId);
if ("111".equals(productId)) { /// productId 가 111이 들어오면 에러로 인시
log.warn("###Received empty body for productId: {}", productId);
throw new RuntimeException("Empty response body");
}
return new Product(
productId,
"Sample Product"
);
}
// Fallback 메서드: getProductDetails 메서드 호출이 실패했을 때 실행
// - productId: 원래 요청에서 사용한 제품 ID
// - t: 발생한 예외 객체로, 실패 원인에 대한 정보를 포함
public Product fallbackGetProductDetails(String productId, Throwable t) {
log.error("####Fallback triggered for productId: {} due to: {}", productId, t.getMessage());
return new Product(
productId,
"Fallback Product"
);
}
Resilience4j
MSA 환경에서 탄력성을 향상시키기 위한 다양한 패턴을 제공하는 경량 라이브러리이다.
서킷 브레이커와 여러 기능을 지원하며 Spring Boot와 자연스럽게 통합된다한다.
람다와 함수형 인터페이스를 지원한다. 서비스간의 호출 실패를 감지하고 시스템의 안정성을 유지할 수 있다.
스프링부트에서는 애너테이션을 사용해 간단하게 적용할 수 있다.
Actuator와 통합으로 모니터링을 가능하게해 서킷 브레이커의 상태를 쉽게 파악할 수 있다.
사용하는 이유는 MSA 안정성 확보, 일시적 장애 극복 등이 있지만 이 둘이 가장 중요한 것 같다.
주요 설정
- 실패율 임계치( failureRateThreshold )
- 서킷 브레이커가 OPEN 상태로 전환될 실패율 기준을 설정한다.
- 요청의 실패율(%)이 이 값을 초과하면 CLOSED 상태에서 OPEN 상태로 전환된다.
- 외부 API 호출에서 일정 비율 이상 실패가 발생한 경우 추가적인 호출을 차단하여 시스템의 안정성을 보장
- 실패율 = (실패한 요청 수 / 슬라이딩 윈도우 내 총 요청 수) x 100
- 슬라이딩 윈도우 ( slidingWindowSize )
- 서킷 브레이커가 실패율을 계산하기 위해 참조하는 요청의 개수 또는 시간 범위를 정의한다.
- 요청 개수를 기준으로 실패율울 계산하는 카운트 기반과 요청 시간 범위를 기준으로 실패율을 계산하는
시간 기반이 있다.
- OPEN 상태 유지 시간 ( waitDurationInOpenState )
- 서킷 브레이커가 OPEN 상태에서 얼마 동안 요청을 차단할지를 설정한다.
- 설정한 시간이 지나면 HALF-OPEN 상태로 전환된다.
- 설정의 숫자는 초 단위이다.
- 너무 짧게 설정하면 서비스가 완전히 복구되지않음에도 HALF-OPEN 상태로 전환될 수 있으니 주의해서 설정해야한다.
의존성 추가
dependencies {
// 서킷 브레이커 사용 (Circuit Breaker)
implementation 'io.github.resilience4j:resilience4j-circuitbreaker:2.0.2'
}
application.yml 설정
resilience4j:
circuitbreaker:
configs:
default: # 기본 구성 이름
registerHealthIndicator: true # 애플리케이션의 헬스 체크에 서킷 브레이커 상태를 추가하여 모니터링 가능
# 서킷 브레이커가 동작할 때 사용할 슬라이딩 윈도우의 타입을 설정
# COUNT_BASED: 마지막 N번의 호출 결과를 기반으로 상태를 결정
# TIME_BASED: 마지막 N초 동안의 호출 결과를 기반으로 상태를 결정
slidingWindowType: COUNT_BASED # 슬라이딩 윈도우의 타입을 호출 수 기반(COUNT_BASED)으로 설정
# 슬라이딩 윈도우의 크기를 설정
# COUNT_BASED일 경우: 최근 N번의 호출을 저장
# TIME_BASED일 경우: 최근 N초 동안의 호출을 저장
slidingWindowSize: 5 # 슬라이딩 윈도우의 크기를 5번의 호출로 설정
minimumNumberOfCalls: 5 # 서킷 브레이커가 동작하기 위해 필요한 최소한의 호출 수를 5로 설정
slowCallRateThreshold: 100 # 느린 호출의 비율이 이 임계값(100%)을 초과하면 서킷 브레이커가 동작
slowCallDurationThreshold: 60000 # 느린 호출의 기준 시간(밀리초)으로, 60초 이상 걸리면 느린 호출로 간주
failureRateThreshold: 50 # 실패율이 이 임계값(50%)을 초과하면 서킷 브레이커가 동작
permittedNumberOfCallsInHalfOpenState: 3 # 서킷 브레이커가 Half-open 상태에서 허용하는 최대 호출 수를 3으로 설정
# 서킷 브레이커가 Open 상태에서 Half-open 상태로 전환되기 전에 기다리는 시간
waitDurationInOpenState: 20s # Open 상태에서 Half-open 상태로 전환되기 전에 대기하는 시간을 20초로 설정
트러블 슈팅
로드밸런싱 테스트 중 발생한 포트번호 문제
복습으로 시작한 미니 프로젝트에서 config server에서 port를 할당받아 product service가 동작하게했다.
로드밸런싱이 잘 동작되는지 확인하기위해 동일한 서버를 다른 port로 열어본다.
강의에서 배운대로 임의의 포트를 지정하고 실행하였다.
기존의 local 설정 파일에서 설정된 product service의 port는 8083이었다. 같은 설정 파일을 사용하면서 인스턴스별로 다른 port를 할당받았다. 이제 로드밸런싱이 잘 동작하는지만 확인하면 된다.
아무리 검색을 하고 생각을 해봐도 내 얕은 지식으로는 tomcat이 왜 실행이 안되는지 모르겠다.
같은 config server를 공유하고 다른 인스턴스 별로 port도 다르게 할당 받았는데 뭐가 문제지? config server에 기능을
내가 잘못 사용하고있나 라고 생각했다. 질문을 머리속에서 다듬고 임은지 튜터님께 찾아가 여쭤보았다.
생각보다 정말 간단한 문제였다.
Tomcat 서버에서 사용할 수 있는 포트 번호의 범위는 기본적으로 운영체제에서 지정한 0 ~ 65535 사이의 값이다.
바보같이 80833 을 지정해 범위를 벗어나 Tomcat 이 유효 port 범위를 할당하지못해 발생한 에러였다.
포트 범위 안인 8084로 변경했다. 이제 product service의 원본 인스턴스는 8083을 복사한 인스턴스는 8084 포트를 할당 받을 것이다. 실행해본다.
같은 config server의 설정을 공유하면서 다른 포트를 가진 두 인스턴스가 정상적으로 동작되는걸 볼 수 있다.
이제 talend api tester 로 요청해본다. 크롬으로 써서 그런지 postman 보다 손이 많이 간다.
해결.
에러의 핵심
1. 포트 번호를 80833으로 설정했기 때문에 문제가 발생.
2. 유효한 포트 범위(0 ~ 65535)를 초과했음.
3. 바보같이 생각을 안함
나는 port 를 변경할 일이 거의 없었다. 그래서 학부에서 배웠지만 잊어버린것이다. 반성해야겠다..
에러 로그를 보고 생각하면 된건데 여러 생각이 꼬리를 물어 바보같이 로그를 볼 생각조차 안하고
무작정 찾아간것 같다 좀 더 신중해야할듯하다.
또 질문을 머리속에서 정리하고 튜터님을 찾아가 질문했지만 생각보다 설명을 못한 것 같다.
개똥같이 말했는데 찰떡같이 알아주셨다.
내가 겪는 문제를 남에게 설명하는 스킬을 키워야겠다.
첫 TIL 작성인데 작성하면서도 배우는게 많은 거 같다 좋은 습관인듯
'MSA' 카테고리의 다른 글
25.03.12 도메인 주도 설계 ( DDD )란? (0) | 2025.03.12 |
---|---|
25.03.11 Kafka 란? (1) | 2025.03.11 |
25.03.10 RabbitMQ 란? (0) | 2025.03.10 |
25.03.06 세션 클러스터링 및 포트 가 다른 서버 간의 세션 공유 (0) | 2025.03.06 |
[MSA] SpringBoot 멀티 모듈 프로젝트 구성 (0) | 2025.02.10 |