ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 서킷 브레이커 구성하기
    프로젝트/선착순 쿠폰 발급 시스템 2023. 2. 28. 00:01
    반응형

    개요

    Client 모듈을 생성 외부 서버를 호출하는 테스트를 수행해 보았습니다.

    하지만 외부 서비스에 장애가 발생하면 어떻게 될까요?

    내부 서비스까지 같이 장애가 전파되어 버릴 수 있습니다.

     

    이를 막는 방법중 하나가 서킷 브레이커입니다.

     

    서킷 브레이커란?

    장애가 특정 임계값에 도달하면 오류와 함께 반환하는 간단한 아이디어입니다.

    메서드 호출이 실패할 때 장애가 연쇄적으로 발생하는 것을 방지하고 실패한 서비스를 복구할 수 있는 시간을 제공합니다.

     

    서킷 브레이커 적용하기

    1. build.gradle.kts 수정

    //Circuit Breaker
    implementation("io.github.resilience4j:resilience4j-spring-boot2:1.7.0")
    
    //kotlin-logging
    implementation("io.github.microutils:kotlin-logging-jvm:2.0.10")
    implementation("org.slf4j:slf4j-api:1.7.30")

    서킷 브레이커와 logging을 위해 의존성을 추가합니다.

    api-external-api 모듈의 build.gradle.kts입니다.

     

    2. application.yml 수정

    resilience4j:
        circuitbreaker:
            instances:
                testClient:
                    ringBufferSizeInClosedState: 10
                    ringBufferSizeInHalfOpenState: 30
                    waitDurationInOpenState: 10000ms
                    failureRateThreshold: 20
                    registerHealthIndicator: false

    이때 testClient는 추후에 사용할 서킷브레이커의 name입니다.

    ringBufferSizeInClosedState는 circuir이 닫혀있을 때 Ring Buffer 사이즈를 뜻합니다.

    ringBufferSizedHalfOpenState half-open 상태일 때 RingBuffer 사이즈이며 기본값은 10입니다.

    waitDurationInOpenState는 half closed전에 circuitBreaker가 open 되기 전에 기다리는 기간입니다.

    failureRateThreshold는 Circuit을 열지 말지 결정하는 실패 threshold 퍼센티지입니다.

     

    위의 설정대로라면 10개의 ringBuffer에서 20 Percent 이상 발생하였을 때 10초 동안 fallback 메시지를 보내고 api가 복구되면 정상적으로 호출되는지 테스트할 수 있습니다.

     

    3. application code 수정

    @RestController
    class TestController(
        private val testClient: TestClient
    ) {
        val logger = KotlinLogging.logger{}
        @CircuitBreaker(name = "testClient", fallbackMethod = "helloFallBack")
        @GetMapping("/test/{params}")
        fun hello(@PathVariable params:String): String{
            val result = testClient.requestDasSample(params)
            logger.info {"Time: ${LocalTime.now()}, result: $result"}
            return "Time: ${LocalTime.now()}, result: $result"
        }
    
        private fun helloFallBack(
            e: Throwable
        ): String{
            logger.info {"Time: ${LocalTime.now()}, test Server is down"}
            return "\"Time: ${LocalTime.now()}, test Server is down"
        }
    }

     

    @CircuitBraker를 통해 testClient라는 네임을 줍니다 (위의 yml설정에서 주었던 이름)

    fallbackMethod는 helloFallBack으로 정의하고 해당 이름과 동일한 메서드를 하나 생성합니다.

    helloFallBack 메서드는 실패 시 반환하는 메서드입니다.

     

    KotlinLogging을 통해 컨트롤러를 호출하였을 때 로깅을 찍고 시간을 포함하여 결과를 반환해봅니다.

     

    서킷 브레이커 테스트

    이전에 Client 모듈을 구성할 때 test/2로 보내면 예외를 발생시키고 test/1로 보내면 정상 응답을 처리하도록 하였습니다.

    localhost:8080/test/2로 3번의 요청을 보내고 나면 서킷브레이커가 발동되어 test/1로 요청을 보내도 10초간 test Server is down이라는 메시지를 반환합니다.

     

    이후 10초의 시간이 지나면 다시 This is Test Server라는 메시지를 정상 응답으로 반환합니다.

     

    결론

    만약 어떤 요청이 10초의 Timeout에 걸쳐 계속 예외를 반환하는 경우 사용자는 계속 10초의 응답을 기다렸다가 예외 메시지를 보게 됩니다.

    이때 서킷브레이커가 걸려있고 임계치 이상 에러가 발생하였다면 10초를 기다리는 것이 아니라 즉각적으로 예외 메시지를 받을 수 있어 사용자가 편의를 느낄 수 있을 것 같습니다.

     

     

    참고자료

    https://wedul.site/654

     

    Spring boot2 resilience4j를 이용한 circuit breaker 사용

    fault tolerance library (장애 허용 시스템) fault tolerance library는 무엇인가? 간단하게 이야기해보자. MSA 환경에서 한 개의 서비스에서 다른 api를 호출 할 때 일시적으로 에러가 발생하고 있다고 가정해

    wedul.site

     

    반응형

    댓글

Designed by Tistory.