Circuit breaker 패턴을 이용한 장애에 강한 MSA 서비스 구현하기 #2
Spring을 이용한 Circuit breaker 구현
조대협 (http://bcho.tistory.com)
앞의 글에서는 넷플릭스 Hystrix를 이용하여 Circuit break를 구현해보았다.
실제 개발에서 Hystix로 개발도 가능하지만, 보통 자바의 경우에는 Spring framework을 많이 사용하기 때문에 이번 글에서는 Spring framework을 이용한 Circuit breaker를 구현하는 방법을 알아보도록 한다.
다행이도 근래에 Spring은 넷플릭스의 MSA 패턴들을 구현화한 오픈 소스들을 Spring 오픈 소스 프레임웍안으로 활발하게 합치는 작업을 진행하고 있어서 어렵지 않게 구현이 가능하다.
구현하고자 하는 시나리오는 앞의 글에서 예제로 사용한 User service에서 Item Service를 호출하는 구조를 구현하고, User service에 circuit breaker를 붙여보도록 하겠다.
User service 코드 전체는 https://github.com/bwcho75/msa_pattern_sample/tree/master/user-spring-hystrix 에 그리고 Item Service 코드 전체는 https://github.com/bwcho75/msa_pattern_sample/tree/master/item-spring-hystrix 에 있다
Spring Circuit breaker 구현
User service pom.xml 정의
Hystrix circuit breaker를 사용하기 위해서는 pom.xml에 다음과 같이 hystrix 관련 라이브러리에 대한 의존성을 정의해줘야 한다.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
<version>1.4.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>1.5.11.RELEASE</version>
</dependency>
spring-cloud-starter-hystrix 는 Hystrix circuit breaker를 이용한 의존성이고 hystrix-dashboard와 actuator 는 hystix dash 보드를 띄우기 위한 의존성이다.
User service 구현
UserApplication
Circuit breaker를 이용하기 위해서는 User Service의 메인 함수인 UserApplication 에 Annotation으로 선언을 해준다.
package com.terry.circuitbreak.User; | |
import org.springframework.boot.SpringApplication; | |
import org.springframework.boot.autoconfigure.SpringBootApplication; | |
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; | |
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard; | |
@SpringBootApplication | |
@EnableCircuitBreaker | |
@EnableHystrixDashboard | |
public class UserApplication { | |
public static void main(String[] args) { | |
SpringApplication.run(UserApplication.class, args); | |
} | |
} |
위의 코드와 같이 @EnableCircuitBreaker Annotation을 추가해주면 Circuit breaker를 사용할 수 있고, 그리고 추가적으로 Hystrix 대쉬 보드를 사용할것이기 때문에, @EnableHystrixDashboard Annotation을 추가한다.
Item Service를 호출
그러면 UserSerivce에서 ItemService를 호출하는 부분을 구현해보도록 하자. Hystrix와 마찬가지로 Spring Hystrix에서도 타 서비스 호출은 Command로 구현한다. 아래는 Item Service에서 Item 목록을 가지고 오는 GetItemCommand 코드이다.
GetItemCommand
Hystrix Command와 거의 유사하지만 Command를 상속 받아서 사용하지 않고, Circuit breaker를 적용한 메서드에 간단하게 @HystrixCommand Annotation만을 추가하면 된다.
아래 코드를 자세하게 보자. 주의할점은 Item Service 호출을 RestTemplate API를 통해서하는데, RestTemplate 객체인 resetTemplate는 Autowrire로 생성한다.
@Service | |
public class GetItemCommand { | |
| |
@Autowired | |
RestTemplate restTemplate; | |
| |
@Bean | |
public RestTemplate restTemplate() { | |
return new RestTemplate(); | |
} | |
// GetItem command | |
@HystrixCommand(fallbackMethod = "getFallback") | |
public List<User> getItem(String name) { | |
List<User> usersList = new ArrayList<User>(); | |
| |
List<Item> itemList = (List<Item>)restTemplate.exchange("http://localhost:8082/users/"+name+"/items" | |
,HttpMethod.GET,null | |
,new ParameterizedTypeReference<List<Item>>() {}).getBody(); | |
usersList.add(new User(name,"myemail@mygoogle.com",itemList)); | |
| |
return usersList; | |
} | |
| |
// fall back method | |
// it returns default result | |
@SuppressWarnings("unused") | |
public List<User> getFallback(String name){ | |
List<User> usersList = new ArrayList<User>(); | |
usersList.add(new User(name,"myemail@mygoogle.com")); | |
| |
return usersList; | |
} | |
} |
Item Service를 호출하는 코드는 getItem(String name) 메서드이다. 여기에 Circuit breaker를 적용하기 때문에, 메서드 앞에 @HystrixCommand(fallbackMethod = "getFallback") Annotation을 정의하였다. 그리고 Item Service 장애시 호출한 fallback 메서드는 getFallback 메서드로 지정하였다.
getItem안에서는 ItemService를 RestTemplate을 이용하여 호출하고 그 결과를 List<User> 타입으로 반환한다.
앞서 정의한 Fallback은 getFallback() 메서드로 Circuit breaker를 적용한 원래 함수와 입력 (String name)과 출력 (List<User>) 인자가 동일하다.
Circuit breaker 테스트
User service와 Item Service를 기동한 상태에서 user service를 호출하면 아래와 같이 itemList에 Item Service가 리턴한 내용이 같이 반환 되는 것을 확인할 수 있다.
terrycho-macbookpro:~ terrycho$ curl localhost:8081/users/terry
[
{
"name":"terry",
"email":"myemail@mygoogle.com",
"itemList":[
{
"name":"computer",
"quantity":1
},
{
"name":"mouse",
"quantity":2
}
]
}
]
Item Service를 내려놓고 테스트를 해보면 지연 응답 없이 User service로 부터 응답이 리턴되고, 앞서 정의한 fallback 메서드에 의해서 itemList에 아무 값이 없인할 수 있다.
terrycho-macbookpro:~ terrycho$ curl localhost:8081/users/terry
[
{
"name":"terry",
"email":"myemail@mygoogle.com",
"itemList":[]
}
]
Hystrix Dashboard
User service에서 Hystrix Dash board를 사용하도록 설정하였기 때문에, User Service의 호출 상태를 실시간으로 확인할 수 있다.
User serivce 서버의 URL인 localhost:8081에서 localhost:8081/hystrix.stream을 호출 해보면
아래와 같이 Circuit Breaker가 적용된 메서드의 상태 현황 정보가 계속해서 업데이트 되면서 출력하는 것을 확인할 수 있다.
그러면 대쉬보드에 접속해보자 대쉬 보드 URL은 http://{user service}/hystrix 이다. User service url이 localhost:8081이기 때문에 http://localhost:8081/hystrix로 접속해보자
대쉬 보드에서는 모니터링 할 서비스의 스트림 URL을 넣어줘야 하는데 위에서 설명한 http://localhost:8081/hystrix.stream 을 입력한다.
URL을 입력하고 모니터링을 하면 아래와 같이 Circuit breaker가 등록된 서비스들이 모니터링 된다.
아래 그림은 부하가 없을때 상태이다.
실제로 부하를 주게 되면 아래와 같이 그래프가 커져가면서 정상적인 호출이 늘어가는 것을 확인할 수 있고, 응답 시간들도 모니터링이 가능하다.
아래는 Circuit breaker를 통해서 호출되는 Item service를 죽였을때인데, 그래프가 붉은색으로 표시되면서 붉은색 숫자가 증가하는 것을 볼 수 있고 Item service가 장애이기 때문에, Circuit 의 상태가 Close에서 Open을 변경된것을 확인할 수 있다.
운영 적용에 앞서서 고려할점
앞에서 예제로 사용한 Dashboard는 어디까지나 테스트 수준에서 사용할만한 수준이지 실제 운영환경에 적용할때는 여러가지 고려가 필요하다. 특히 /hystrix , /hystrix.stream이 외부에서 접근이 가능하기 때문에,, 이에 대해서 이 두 URL이 외부로 접근하는 것을 막아야 하며, circuit의 상태에 대한 정보를 하나의 서비스만 아니라 여러 서비스에서 대용량 서비스에 적용할시에는 중앙 집중화된 대쉬보드가 필요하고 또한 많은 로그를 동시에 수집해야 하기 때문에, 대용량 백앤드가 필요하다. 이를 지원하기 위해서 넷플릭스에서는 터빈 (Turbine)이라는 이름으로, 중앙 집중화된 Hystrix 대쉬 보드 툴을 지원하고 있다. (https://github.com/Netflix/turbine/wiki)
이번 글에서는 Spring 프레임웍을 이용하여 Circuit breaker 패턴을 Hystrix 프레임웍을 이용하여 적용하는 방법을 알아보았다.
Spring을 사용하면 편리는 하지만 자바 스택만을 지원한다는 한계점을 가지고 있다. Circuit breaker를 이처럼 소프트웨어로 지원할 수 도 있지만, 소프트웨어가 아닌 인프라 설정을 이용해서 적용이 가능한데, envoryproxy 를 이용하면 코드 변경 없이 모든 플랫폼에 적용이 가능하다. 다음 글에서는 envoy proxy를 이용하여, circuit breaker를 사용하는 방법에 대해서 알아보도록 한다.
'아키텍쳐 > 대용량 아키텍쳐' 카테고리의 다른 글
MSA를 위한 L7 Proxy - EnvoyProxy #1 (0) | 2018.05.08 |
---|---|
MSA에서 Service discovery 패턴 (0) | 2018.04.18 |
Circuit breaker 패턴을 이용한 장애에 강한 MSA 서비스 구현하기 #1 - Circuit breaker와 넷플릭스 Hystrix (1) | 2018.04.04 |
분산 로그 & 데이타 수집기 Fluentd (2) | 2016.06.13 |
REST API의 이해와 설계 (2) | 2016.04.05 |