[Spring Cloud] - 7. Hystrix를 이용한 Circuit Breaker (기본편)

지난 포스트에 이어서 Spring Cloud에서 Circuit Breaker를 구현할 수 있는 첫 번째 파트를 들어가보도록 하겠습니다.

 

Hystrix

Hystrix는 Spring Cloud 스택에서 제공하는 Circuit Breaker 중 하나입니다. Netflix에서 개발했으며 현재는 Spring Cloud의 표준 Circuit Breaker로 자리 잡고 있죠.

기본적으로 Hystrix는 위와 같은 형태로 동작합니다. 브라우저 혹은 모바일에서 어떤 API 요청이 들어왔을 경우, 해당 서비스의 엔드포인트가 호출되는데, 이 때 서비스에 오류가 발생했거나 응답이 없을 경우, 이후 이용자에게 장애가 전파되지 않고, 미리 정의된 오류를 브라우저 혹은 모바일에서 전송하게 되어 오류 전파를 막아주게 됩니다.

그러면 구체적으로 Hystrix는 어떻게 동작이 되는 것일까요? 

먼저 HystrixCommand, HystrixObservableCommand 객체가 생성되고, Command가 실행됩니다.

만약, 기존에 이미 요청한 적이 있고, 그 결과가 캐시에 저장되어 있다면 그 결과를 그대로 전송합니다. 그렇지 않다면, 서비스의 동작 여부, 오류 상태를 확인하게 되고, 그것이 정상임을 확인했다면, 이제 Thread Pool, Queue, Semaphore가 있는지를 확인하는데, 이 과정이 중요합니다. 만약, Circuit Breaker 인스턴스에서도 이러한 운영체제 자원이 없다면, 오류가 발생하게 됩니다.

여기서 이 부분이 중요한데, Spring Application을 개발하고, 여러 사람이 접속하게 되면, 정해진 Thread 자원을 다 쓰게 되는 드의 문제가 자주 발생하게 됩니다. 특히 Socket과 같은 통신의 경우는 Linux Kernel에 영향을 많이 받기 때문에 실질적으로 많이 문제가 생기므로 Hystrix에서도 이러한 오류 처리를 반드시 거쳐야 합니다.

자원 확보가 확인되었다면, API 서비스에 요청을 전달하게 되고, 오류가 발생했다면 Fallback 함수를 통해 오류를 전달하고, 그렇지 않을 경우, 그 결과를 그대로 브라우저에 전달하게 되는 역할을 하게 됩니다.

 

How to use

이제 간단한 사용법을 알아볼텐데, 이번 포스트에서는 Zuul Gateway, Eureka 등의 서비스 없이 단순히 API 서비스만 가지고 사용하는 방법에 대해 알아볼 것입니다.

먼저 Circuit Breaker 역할을 해줄 새로운 프로젝트를 생성합니다. 그러고 난 후, 아래의 디펜던시를 추가해줍시다.

implementation("org.springframework.boot:spring-boot-starter-webflux")
implementation("org.springframework.cloud:spring-cloud-starter-netflix-hystrix")

각 디펜던시를 간단히 설명드리자면, WebFlux는 Spring에서 REST API Client 라이브러리입니다. 본래 RestTemplate이라는 라이브러리가 있지만, 이 포스트에서는 WebFlux 라이브러리로 진행하겠습니다.

Hystrix가 바로 우리가 사용할 Circuit Breaker입니다.

@EnableHystrix
@SpringBootApplication
class HystrixexampleApplication

fun main(args: Array<String>) {
    runApplication<HystrixexampleApplication>(*args)
}

Application 클래스에 @EnableHystrix 어노테이션을 추가해줍니다.

/**
 * Created by Neon K.I.D on 3/27/20
 * Blog : https://blog.neonkid.xyz
 * Github : https://github.com/NEONKID
 */
@Service
class MemberResource {
    private var client = WebClient.builder().baseUrl("http://localhost:8080").build()

    @HystrixCommand(commandKey = "getNotes", fallbackMethod = "defaultMembers")
    fun getMembers()
            = client.get().uri("/v1/member/detail").retrieve().bodyToMono(String::class.java).block();

    fun defaultMembers() = "ERROR"
}

그런 다음 새로운 컴포넌트를 위와 같이 추가해줍니다.

코드에 대해서 간략하게 설명하자면, 이 컴포넌트는 실제로 브라우저나 모바일에서 호출할 API 함수입니다. Hystrix는 Java 코드에서 Component, Service를 찾고, 그 안에 있는 HystrixCommand 어노테이션에 따라 동작하는 구조로 되어 있습니다. 따라서 API 서버에 있는 내용을 가져오고자 할 때는 Component 내지 Service 어노테이션을 사용하도록 합시다.

대충 눈치를 채셨겠지만, 만약 Member API에서 Member를 가져오는 데, 실패했을 경우, fallbackMethod를 지정할 수 있습니다. 기본적으로 getMembers 메소드를 호출하겠지만, 만약 서킷이 Open되었거나 요청에 실패했을 경우, defaultMembers 메소드가 호출되게 됩니다.

/**
 * Created by Neon K.I.D on 3/28/20
 * Blog : https://blog.neonkid.xyz
 * Github : https://github.com/NEONKID
 */
@RestController
class MemberController {
    @Autowired
    private lateinit var memberResource: MemberResource

    @GetMapping(value = ["/members"])
    fun getMembers() = memberResource.getMembers()
}

마지막으로 REST API를 구현하면 끝입니다.

 

Test

이제 테스트를 진행해보도록 하겠습니다. 테스트를 진행하기 위해 먼저 지난 포스트에서 만들었던 Member API 서비스를 실행시키고, Circuit Breaker를 실행해 봅시다.

두 서비스 모두 같은 명령을 호출하고 있음을 알 수 있습니다. 이제 API 서비스를 한 번 종료한 후, 결과를 보도록 하죠.

Member API 서비스는 연결이 끊어진 상태이고, Circuit Breaker가 이에 따라 정의된 함수를 호출하여 ERROR를 출력해주고 있습니다.

 

마치며...

여기까지 Hystrix의 간단한 사용법에 대해 알아봤습니다. 아마 실습하시는 동안 많은 의문점이 드셨을 수도 있을 것입니다. 이전까지는 Zuul Gateway를 이용해 각각 떨어진 API들을 묶어주고 이를 덧붙여 로드 밸런싱된 인스턴스들을 Eureka가 찾아주었는데, 여기에 Circuit Breaker까지 붙으면? 흠..

사실 저의 Spring Cloud의 포스트는 Zuul Gateway까지가 가장 기본적인 형태로 진행될 예정이었습니다. Circuit Breaker는 옵션인 형태로 제공될 예정이었습니다만 그 이유는 Circuit Breaker는 다양한 형태로 구현될 수 있기 때문입니다. 여러분들이 원한다면 Circuit Breaker를 앞에 붙여놓고 단독으로 사용할 수 있고, Zuul Gateway, Riboon 등 다양한 컴포넌트와 묶어서도 사용할 수 있습니다.

이 외에도 오류 처리를 위해 다양한 통계를 집계해서 시각화 해주는 대시보드, Hystrix의 튜닝 등 다양한 것들이 많이 있어서 Hystrix는 사용하기도 그만큼 어렵고, 깊은 분야입니다. 따라서 기본편에서는 이런 처리를 기본적으로 제공하고, 더 나아가서는 내 서비스에 어떤 식으로 적용해야 할 지를 고민하셔야 할 것입니다.

 

이미지 출처

(https://cloud.spring.io/spring-cloud-netflix/multi/multi__circuit_breaker_hystrix_clients.html)

(https://github.com/Netflix/Hystrix/wiki/How-it-Works)

TAGS.
comments powered by Disqus

Tistory Comments 0