🎩 장애 발생
- UserService를 잘 사용하다가 OrderService나 CatalogService에서 장애가 발생하여 데이터를 전달 받지 못하게 된다면 그것은 해당 서비스의 문제가 된다. 하지만 중요한것은 반환값이다. 요청에 의한 응답엔 UserService가 문제가 발생했다고 얘기한다는 말이다.
- 그렇기 때문에 UserService 혹은 다른 서비스들도 그에 대한 대비가 되어있어야 한다. UserService에서 보이는 getOrders가 문제가 발생하면 다른 메소드를 호출해서 데이터를 처리하여 안정적으로 응답을 해야 한다는 말이다. 그러면 정상적인 응답이 전송될것이다. 하지만 문제가 발생한 Order쪽의 데이터는 정확하지 않게 되면서 우리는 Order서비스가 문제가 발생한 것을 알 수 있고 UserService는 OrderService에 장애에 대한 타격을 받지 않는 상태가 될 수 있다.
🎩 CircuitBreaker의 사용
- 우리는 정상적으로 응답하지 못하는 서비스의 응답을 계속해서 요청하면 소용이 없다는 것을 알기때문에 해당 서비스가 문제가 없기 전까지 다시 요청을 보내는 일이 없을 것이다. 그걸 위해 사용하는 것이 바로 CircuitBreaker이다
- CircuitBreaker는 장애가 발생한 서비스를 감지하고 더 이상 요청을 보내지 않도록 차단하고 장애가 퍼지지 않도록 격리시키는 하나의 패턴이다.
- CircuitBreaker는 장애가 발생하는 서비스에 반복적인 호출이 되지 않게 하기 위해 차단한다
- 특정 서비스가 정상적으로 동작하지 않는 경우(Timeout OR Error) 다른 기능으로 대체 수행된다
- 서킷브레이커는 실패할 가능성이 존재하는 작업을 수행하는 행위를 방지한다.
- 실패할 수 있는 작업에 대한 프록시 역할을 하고 최근 실패 수를 모니터링 하여 작업의 지속여부 또는 단순히 예외를 즉시 반환할지 결정하게 된다.
- Close : 서킷브레이커가 닫혔다. 즉, 서비스의 문제가 없기때문에 사용하지 않는 상태이다 그러나 오류가 임계치를 초과하면 회로 차단기가 작동하고 회로의 상태가 open으로 변한다
- Open : 서킷브레이커가 작동중이다. 서비스의 문제가 발생했다는 뜻이다. 서킷브레이커는 기본값이나 우회할 수 있는 값을 반환해준다. (fallback)
- Half-open : 열림상태에서 일정한 시간을 설정하고 그 시간이 지나면 해당 상태로 변한다. 이 상태에 회로 차단기는 제한된 수의 테스트 요청을 통과하도록 허용하고 요청이 성공한다면 닫힌 상태로 돌아간다. 하지만 또 다시 실패한다면 다시 제한시간이 설정되고 open 상태로 변경된다.
🎩 Resilience4J의 사용
Netflix Hystrix에서 영감을 받았지만 함수형 프로그래밍을 위해 설계된 가벼운 내결함성 라이브러리이다 실제로는 다양한 핵심 모듈이 있지만 우린 그중 CircuitBreaker를 이용해서 테스트를 진행한다.
- 유한한 상태를 가지고 주어지는 입력에 따라 어떤 상태에서 다른 상태로 전환하고 액션이 일어나게 하는 모델의 이름을 유한 상태머신 이라고 한다 Resilience는 이를 통해 구현되고 개수 기반 슬라이딩 윈도우, 시간 기반 슬라이딩 윈도우를 통해 결과를 저장하고, 집계한다.
● 개수(카운트) 기반 슬라이딩 윈도우
일정 개수의 요청을 추적하고, 해당 요청들 중 실패한 요청의 비율을 계산하고 회로를 차단한다.
즉, 일정 윈도우 크기만큼을 기준으로 임계치를 계산하는 것이다. 예를 들어 10개의 윈도우에서 2번쨰 요청의 실패가 존재한다면 임계치는 10%로 결정되지만 다음 요청때 맨 앞의 요청이 제거되고 총 20%의 임계치가 된다
● 시간 기반 슬라이딩 윈도우
기본적으로 슬라이딩 윈도우의 개념은 비슷하지만 이를 일정 시간 동안의 요청에 대한 추적을기준으로 한다는 점이 매우 다르다.
즉, 슬라이딩 윈도우의 길이를 정하고 해당 기간 (ex 5분)동안의 실패율을 계산해서 임계치를 계산한다.
🎩 실습
♬ 오류 발생
- 우선 우리는 Order를 사용하지 않고 UserService를 이용해보고자 한다. 우리는 로그인까지 진행하고 사용자의 정보를 가져오려고 한다면 해당 오류가 발생할 것이다.
- 바로 OrderService의 내용을 가져올 수 없다는 뜻이다. 그렇기 떄문에 우린 Resilience4J를 설치하고 circuitBreaker를 사용해보고자 한다
♬ 코드 추가
- 라이브러리 추가
- UserService에 spring-cloud가 제공하는 spring-cloud-starter-circuitbreaker-resilience4j 라는 의존성을 추가해준다
- ServiceImpl 코드 변경
- 기존에 그냥 getOrders를 통해 데이터를 가져왔지만 이를 circuitbreaker를 통해 가져오게 되면서 새롭게 작성을 해주어야 한다.
- 밑의 사진을 보면 circuitbreakerFactory를 추가하고 의존성을 추가해주고 circuitbreaker를 하나 만들어준다 그리고 run이라는 메소드를 통해 원래 하려는 작업을 진행하고 만약 문제가 생길경우 빈 ArrayList를 반환하는 것을 알 수 있다.
- 결과
- 똑같이 진행했지만 이전과는 다르게 orders의 문제와는 별개로 데이터는 반환한다는 것을 확인 할 수 있다
- 그렇다고 UserService의 콘솔에 발생하는 에러까지 없어지는 것이 아니다.
♬ circuitBreaker 설정
- 위에서 부터 천천히 설명을 해보자면 우린 Circuitbreaker 설정을 직접해주기 위해서 Config 클래스를 새로 만들어주었다.
- 사진에서 보다시피 Customizer를 할 것이기에 임포트를 해주는데 정확히 해주어야 한다.
- circuitBreakerConfig
- failureRateThreshold : 서킷 브레이커를 열지 결정하는 것이다. 기본은 50으로 설정되어 있다
- waitDurationInOpenState : 서킷 브레이커를 open한 상태를 유지하는 지속 기간이다. 이후에는 half-open된다
- slidingWindowType : 서킷 브레이커가 닫힐때 통화 결과를 기록하는데 사용되는 슬라이딩 창의 유형이다. 위에서 말한것처럼 카운트 혹은 시간 기반이다.
- slidingWindowSize : 서킷 브레이커가 닫힐 때 호출 결과를 기록하는데 사용되는 슬라이딩 창의 크기를 구성한다.
- timeLimiterConfig
- timeoutDuration : future supplier의 time limit을 정하는 API이다.
♬ circuitBreaker 설정 후 테스트
- 테스트를 진행하기 전에 서킷 브레이커의 작동은 앞서 잘 작동하는 것을 확인했다 그리고 OrderService를 정상적으로 작동시켜 다른 테스트를 진행할 것이다
- 이때 Kafka와 연동되어있는 코드는 모두 주석으로 처리하고 JPA를 사용한 코드만 남겨 실행을 할 것이다. 또한 그로인해 DB또한 Maria에서 다시 h2 로 변경해주어야 한다.
- 그결과는 역시 잘 작동되는 것을 확인 할 수있다.
- 그렇다면 OrderService를 종료하고 다시 사용자의 정보를 불러온다면 빈 값을 내보내는 것으로 확인이 가능하다.
결과적으로 우린 이제 UserService에 요청을 전달하고 전달 받는 과정에서 UserService가 아닌 다른 곳에서 발생한 문제때문에 UserService가 먹통이 되는 것이 아니라 Circuitbreaker를 통해 우선 다른 값으로 전달을 하고 문제가 발생한 곳을 서비스의 서버로 돌아가 확인 할 수 있다는 것이였다. 이로 인해 서버의 결합도를 한층더 맞췄다는 것을 알 수 있다.
'MSA > MSA 강좌 - 이도원 강사님' 카테고리의 다른 글
👨👧👦13. 프로메테우스와 그라파나 (0) | 2024.04.12 |
---|---|
👨👧👦 분산 추척, Zipkin (1) | 2024.04.12 |
👨👧👦11. 데이터 동기화를 위한 Apache Kafka활용하기 (2) (0) | 2024.04.11 |
👨👧👦10. 데이터 동기화를 위한 Apache Kafka활용하기 (1) (0) | 2024.04.09 |
👨👧👦9. Microservice간의 통신 (RestTemplate & FeignClient) (0) | 2024.04.04 |