블로그 이미지
평범하게 살고 싶은 월급쟁이 기술적인 토론 환영합니다.같이 이야기 하고 싶으시면 부담 말고 연락주세요:이메일-bwcho75골뱅이지메일 닷컴. 조대협


Archive»


 
 


MSA에서 Service discovery 패턴의 이해


조대협 (http://bcho.tistory.com)


MSA와 같은 분산 환경은 서비스 간의 원격 호출로 구성이 된다. 원격 서비스 호출은 IP 주소와 포트를 이용하는 방식이 되는다.

클라우드 환경이 되면서 서비스가 오토 스케일링등에 의해서 동적으로 생성되거나 컨테이너 기반의 배포로 인해서, 서비스의 IP가 동적으로 변경되는 일이 잦아졌다.


그래서 서비스 클라이언트가 서비스를 호출할때 서비스의 위치 (즉 IP주소와 포트)를 알아낼 수 있는 기능이 필요한데, 이것을 바로 서비스 디스커버리 (Service discovery)라고 한다.


다음 그림을 보자 Service A의 인스턴스들이 생성이 될때, Service A에 대한 주소를 Service registry (서비스 등록 서버) 에 등록해놓는다. Service A를 호출하고자 하는 클라이언트는 Service registry에 Service A의 주소를 물어보고 등록된 주소를 받아서 그 주소로 서비스를 호출한다.


Client side discovery vs server side discovery

이러한 Service discovery 기능을 구현하는 방법으로는 크게 client discovery 방식과 server side discovery 방식이 있다.

앞에서 설명한 service client가 service registry에서 서비스의 위치를 찾아서 호출 하는 방식을 client side discovery 라고 한다.


다른 접근 방법으로는 호출이 되는 서비스 앞에 일종의 proxy 서버 (로드밸런서)를 넣는 방식인데, 서비스 클라이언트는 이 로드밸런서를 호출하면 로드밸런서가 Service registry로 부터 등록된 서비스의 위치를 리턴하고, 이를 기반으로 라우팅을 하는 방식이다.



가장 흔한 예제로는 클라우드에서 사용하는 로드밸런서를 생각하면 된다. AWS의 ELB나 구글 클라우드의 로드 밸런서가 대표적인 Server side discovery 방식에 해당 한다.

Service registry

그러면 서비스를 등록하는 Service registry는 어떻게 구현을 해야 할까?

가장 쉬운 방법으로는 DNS 레코드에 하나의 호스트명에 여러개의 IP를 등록하는 방식으로 구현이 가능하다. 그러나 DNS는 레코드 삭제시 업데이트 되는 시간등이 소요되기 때문에, 그다지 적절한 방법은 아니기 때문에, 솔루션을 사용하는 방법이 있는데, ZooKeeper나 etcd 와 같은 서비스를 이용할 수 있고 또는 Service discovery에 전문화된 솔루션으로는 Netflix의 Eureka나 Hashcorp의 Consul과 같은 서비스가 있다.


향상된 기능

Service discovery 기능은 기본적으로 서비스를 등록하고 등록된 서비스의 목록을 리턴하는 기능이지만, 지능화된 기능을 이용하여 조금 더 향상된 기능을 제공할 수 있다.

예를 들어 Service registry에 등록된 서비스들의 Health check를 통해서 현재 서비스가 가능한 서비스를 판별한후, 서비스가 가능한 서비스 목록만 리턴을 한다던가. 서비스간의 부하 분산 비율을 조정하는 등의 고급 기능을 추가할 수 있고, 서버 목록에서 Master/Slave 서버의 정보를 리턴한다던가. 또는 서버에 접속하기 위한 인증키 정보등을 리턴하는 기능등 다양한 기능으로 확장이 가능하다.


참고 자료


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를 사용하는 방법에 대해서 알아보도록 한다.

Circuit breaker 패턴을 이용한 장애에 강한 MSA 서비스 구현하기 #1

Circuit breaker와 넷플릭스 Hystrix

조대협 (http://bcho.tistory.com)

MSA에서 서비스간 장애 전파

마이크로 서비스 아키텍쳐 패턴은 시스템을 여러개의 서비스 컴포넌트로 나눠서 서비스 컴포넌트간에 호출하는 개념을 가지고 있다. 이 아키텍쳐는 장점도 많지만 반대로 몇가지 단점을 가지고 있는데 그중에 하나는 하나의 컴포넌트가 느려지거나 장애가 나면 그 장애가난 컴포넌트를 호출하는 종속된 컴포넌트까지 장애가 전파되는 특성을 가지고 있다.


이해를 돕기 위해서 아래 그림을 보자


Service A가 Service B를 호출하는 상황에서 어떤 문제로 인하여 Service B가 응답을 못하거나 또는 응답 속도가 매우 느려진 상황이라고 가정하자. Service A가 Service B에 대한 호출 시도를 하면, Service A에서 Service B를 호출한 쓰레드는 응답을 받지 못하기 때문에, 계속 응답을 기다리는 상태로 잡혀있게 된다. 지속해서 Service A가 Service B를 호출을 하게 되면 앞과 같은 원리로 각 쓰레드들이 응답을 기다리는 상태로 변하게 되고 결과적으로는 남은 쓰레드가 없어서 다른 요청을 처리할 수 없는 상태가 된다.

이렇게 Service B의 장애가 Service A에 영향을 주는 경우를 장애가 전파 되었다고 한다. 이 상황에서 Service A를 호출하는 서비스가 또 있다면, 같은 원리로 인하여 그 서비스까지 장애가 전파되서 전체 시스템이 장애 상태로 빠질 수 있다.

Circuit breaker 패턴

이런 문제를 해결하는 디자인 패턴이 Circuit breaker 라는 패턴이 있다.

기본적인 원리는 다음과 같다. 서비스 호출 중간 즉 위의 예제에서는 Service A와 Service B에 Circuit Breaker를 설치한다. Service B로의 모든 호출은 이 Circuit Breaker를 통하게 되고 Service B가 정상적인 상황에서는 트래픽을 문제 없이 bypass 한다.

.


만약에 Service B가 문제가 생겼음을 Circuit breaker가 감지한 경우에는 Service B로의 호출을 강제적으로 끊어서 Service A에서 쓰레드들이 더 이상 요청을 기다리지 않도록 해서 장애가 전파하는 것을 방지 한다. 강제적으로 호출을 끊으면 에러 메세지가 Service A에서 발생하기 때문에 장애 전파는 막을 수 있지만, Service A에서 이에 대한 장애 처리 로직이 별도로 필요하다.

이를 조금 더 발전 시킨것이 Fall-back 메시징인데, Circuit breaker에서 Service B가 정상적인 응답을 할 수 없을 때, Circuit breaker가 룰에 따라서 다른 메세지를 리턴하게 하는 방법이다.



예를 들어 Service A가 상품 목록을 화면에 뿌려주는 서비스이고, Service B가 사용자에 대해서 머신러닝을 이용하여 상품을 추천해주는 서비스라고 했을때, Service B가 장애가 나면 상품 추천을 해줄 수 없다.

이때 상품 진열자 (MD)등이 미리 추천 상품 목록을 설정해놓고, Service B가 장애가 난 경우 Circuit breaker에서 이 목록을 리턴해주게 하면 머신러닝 알고리즘 기반의 상품 추천보다는 정확도는 낮아지지만 최소한 시스템이 장애가 나는 것을 방지 할 수 있고 다소 낮은 확률로라도 상품을 추천하여 꾸준하게 구매를 유도할 수 있다.


이 패턴은 넷플릭스에서 자바 라이브러리인 Hystrix로 구현이 되었으며, Spring 프레임웍을 통해서도 손쉽게 적용할 수 있다.

이렇게 소프트웨어 프레임웍 차원에서 적용할 수 있는 방법도 있지만 인프라 차원에서 Circuit breaker를 적용하는 방법도 있는데, envoy.io 라는 프록시 서버를 이용하면 된다.

소프트웨어를 사용하는 경우 관리 포인트가 줄어드는 장점은 있지만, 코드를 수정해야 하는 단점이 있고, 프로그래밍 언어에 따른 종속성이 있다.

반대로 인프라적인 접근의 경우에는 코드 변경은 필요 없으나, Circuit breaker용 프록시를 관리해야하는 추가적인 운영 부담이 늘어나게 된다.


이 글에서는 넷플릭스의 Hystrix, Spring circuit breaker를 이용한 소프트웨어적인 접근 방법과 envoy.io를 이용한 인프라적인 접근 방법 양쪽을 모두 살펴보기로 한다.


넷플릭스 Hystrix

넷플릭스는 MSA를 잘 적용하고 있는 기업이기도 하지만, 적용되어 있는 MSA 디자인 패턴 기술들을 오픈소스화하여 공유하는 것으로도 유명하다. Hystrix는 그중에서 Circuit breaker 패턴을 자바 기반으로 오픈소스화한 라이브러리이다.  


Circuit breaker 자체를 구현한것 뿐만 아니라, 각 서비스의 상태를 한눈에 알아볼 수 있도록 대쉬보드를 같이 제공한다.


Hystrix 라이브러리 사용방법

Hystrix를 사용하기 위해서는 pom.xml에 다음과 같이 라이브러리 의존성을 추가해야 한다.

<dependency>

<groupId>com.netflix.hystrix</groupId>

<artifactId>hystrix-core</artifactId>

<version>1.5.4</version>

</dependency>

<dependency>

<groupId>com.netflix.rxjava</groupId>

<artifactId>rxjava-core</artifactId>

<version>0.20.7</version>

</dependency>


Circuit breaker는 Hystrix 내에서 Command 디자인 패턴으로 구현된다. 먼저 아래 그림과 같이 HystrixCommand 클래스를 상속받은 Command 클래스를 정의한 후에, run() 메서드를 오버라이드하여, run 안에 실제 명령어를 넣으면 된다. HystrixCommand 클래스를 상속받을때 runI()메서드에서 리턴값으로 사용할 데이타 타입을 <>에 정의한다.


public class CommandHelloWorld extends HystrixCommand<String>{

private String name;

CommandHelloWorld(String name){

super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));

this.name = name;

}

@Override

protected String run() {

return "Hello" + name +"!";

}


이렇게 Command가 정의되었으면 호출 방법은 아래와 같다.


CommandHelloWorld helloWorldCommand = new CommandHelloWorld("World");

assertEquals("Hello World", helloWorldCommand.execute());


먼저 Command 클래스의 객체를 생성한 다음에, 객체.execute()를 이용해서 해당 command 를 실행하면 된다. 이렇게 하면, Command 클래스가 응답을 제대로 받지 못할때는 Circuit Breaker를 이용하여 연결을 강제적으로 끊고 에러 메세지등을 리턴하도록 된다.


전체 코드 샘플은 https://github.com/bwcho75/msa_pattern_sample/tree/master/hystrix 를 참고하기 바란다.

웹서비스에 적용하는 방법

대략적인 개념을 이해하였으면 실제로 이 패턴을 REST API로 구성된 MSA 기반의 서비스에 적용해보자.

두 개의 서비스 User와 Item이 있다고 가정하자 User 서비스가 REST API 호출을 이용하여 Item 서비스를 호출하는 구조라고 할때 이 User → Item 서비스로의 호출을 HystrixCommand를 이용하여 Circuit breaker로 구현해보도록 하자.


User 서비스의 전체 코드는 https://github.com/bwcho75/msa_pattern_sample/tree/master/UserService , Item 서비스의 전체코드는 https://github.com/bwcho75/msa_pattern_sample/tree/master/ItemService 에 있다.

각 코드는 Spring Web을 이용하여 구현되었으며 User → Item으로의 호출을 resttemplate을 이용하였다.


User → Item 서비스를 호출하여 해당 사용자에 속한 Item 목록을 읽어오는 Command를 GetCommand라고 하자, 코드는 대략 아래와 같다.


public class GetItemCommand extends HystrixCommand<List<User>>{

String name;

public GetItemCommand(String name) {

super(HystrixCommandGroupKey.Factory.asKey("ItemServiceGroup"));

this.name = name;

}


@Override

protected List<User> run() throws Exception {

List<User> usersList = new ArrayList<User>();

// call REST API

                                                (생략)

return usersList;

}

@Override

protected List<User> getFallback(){

List<User> usersList = new ArrayList<User>();

usersList.add(new User(name,"myemail@mygoogle.com"));

return usersList;

}

}


리턴 값이 List<User>이기 때문에, HystrixCommand <List<User>>를 상속하여 구현하였고, Item 서비스를 호출하는 부분은 run() 메서드에 구현한다. (restTemplate을 이용하여 호출하는 내용은 생략하였다.)


여기서 주목해야할 부분은 getFallBack() 함수인데, 호출되는 서비스 Item이 장애 일때는 이를 인지하고 getFallBack의 리턴값을 fallback 메세지로 호출한다.


Item과 User 서비스를 각각 실행한다.

%java -jar ./target/User-0.0.1-SNAPSHOT.jar

%java -jar ./target/Item-0.0.1-SNAPSHOT.jar


두 서비스를 실행 한후에 아래와 같이 User 서비스를 호출하면 다음과 같이 ItemList가 채워져서 정상적으로 리턴되는 것을 볼 수 있다.


terrycho-macbookpro:~ terrycho$ curl localhost:8081/users/terry

[{"name":"terry","email":"myemail@mygoogle.com","itemList":[{"name":"computer","qtetertertertertetttt


Item 서비스 서버를 인위적으로 죽인 상태에서 호출을 하면 다음과 같이 위에서 정의한 fall back 메세지와 같이 email이 “myemail@mygoogle.com”으로 호출되고 itemList는 비어 있는채로 리턴이 된다.


terrycho-macbookpro:~ terrycho$ curl localhost:8081/users/terry

[{"name":"terry","email":"myemail@mygoogle.com","itemList":[]}]


지금까지 간단하게나마 Circuit breaker 패턴과 넷플릭스의 Hystrix 오픈소스를 이용하여 Circuit breaker를 구현하는 방법에 대해서 알아보았다.

서비스 상태에 따라서 Circuit을 차단하는 방법등도 다양하고, Command 패턴을 처리하는 방법 (멀티 쓰레드, 세마포어 방식)등이 다양하기 때문에, 자세한 내부 동작 방법 및 구현 가이드는 https://github.com/Netflix/Hystrix/wiki/How-it-Works 를 참고하기 바란다.


Circuit breaker 패턴은 개인적인 생각에서는 MSA에서는 거의 필수적으로 적용해야 하는 패턴이라고 생각을 하지만 Hystrix를 이용하면 Command를 일일이 작성해야 하고, 이로 인해서 코드 복잡도가 올라갈 수 있다. 이를 간소화 하기 위해서 Spring 오픈소스에 이 Hystrix를 잘 추상화 해놓은 기능이 있는데, 그 부분 구현에 대해서는 다음글을 통해서 살펴보도록 한다.



다르게 생각해볼만한 클라우드 컴퓨팅 활용 전략


조대협 (http://bcho.tistory.com)


근래에 스타트업 기반의 빠른 속도의 개발을 경험하고, 클라우드 컴퓨팅 도입 전략에 대해서 고민할 기회가 생겨서 여러 자료를 검토하던중에 퍼블릭 클라우드 도입 전략에 대해서 기존과 다른 접근 방식이 필요하다고 생각되어 그 내용을 정리합니다.


특정 벤더의 의존성 배제


퍼블릭 클라우드 하면 거의 공식 처럼 AWS 클라우드가 소위 말해서 갑이었으나, 근래에 들어서 구글이나 마이크로소프트가 큰 딜을 잡아나가면서 약간씩 구도가 바뀌고 있는 형상이다.  

 특히 구글의 Spotify와, Quizlet의 사례를 보면 구글 사용사례이기 때문에 구글이 좋다는 이야기지만, 내용을 디테일하게 살펴보면 꽤나 재미 있는 인사이트를 얻을 수 있다.

  • Quizlet의 사례 https://quizlet.com/blog/whats-the-best-cloud-probably-gcp
  • Spotify의 사례 https://news.spotify.com/us/2016/02/23/announcing-spotify-infrastructures-googley-future/




Quizlet의 사례는 가격과 성능에 대한 이야기인데 내용을 요약하면 비슷한 VM이면 구글이 더 싸고 성능 (CPU,메모리, 네트워크)이 훨씬 좋다는 것이다. 아마존은 다양한 가격정책으로 다양한 컴퓨팅 파워를 제공하지만 그만큼 세밀한 가격 정책에 의해서, 높은 성능을 내려면 그만큼 추가 상품을 사야 하는데 비해서, 구글의 경우에는 기본 VM들의 네트워크가 IO 성능들이 높다는 것이다.


여기서 구글의 우수성을 보는것 보다, 이게 왜 좋은지에 대한 인사이트를 얻어야 하는데, 아마존은 다른 클라우드 벤더에 비해서 포트폴리오가 매우 다양하다. 인코딩, IAM, 하드웨어 기반의 키 보안 기술 등 그래서 한번 특정 클라우드에 들어가면 다른 클라우드로 옮기기가 쉽지 않은게 사실인데, 잘 생각해보면, 근래의 클라우드 기반의 아키텍쳐는 다음과 같은 트렌드를 갖는다.


VM위에 직접 설치해서 사용


EC2와 같은 VM만 있으면 그위에 직접 소프트웨어를 설치해서 운영을 하면 된다는 것이다. 아마존에서 제공하는 RDS나 RedShift 와 같은 서비스도 결국은 MySQL이나 Postgres와 같은 오픈 소스 기반이고 대부분이 오픈소스나 기존 제품을 기반으로 되어있기 때문에 교체가 가능하다는 것이다. 강한 기술조직을 가지고 있는 기업의 경우 직접 이러한 제품들을 설치 및 운영이 가능하기 때문에 특정 벤더에 Lock in이 되는것을 최소화할 수 있다.

단 이런 소프트웨어를 설치해서 사용하기 위해서는 VM 자체의 성능과 가격이 중요해진다. 네트워크나 디스크 IO의 속도나 GPU 지원 여부등이 중요한 판단 포인트로 작용을 하게 된다.


즉 이 이야기는 EC2와 같은 컴퓨팅과 S3와 같은 스토리지와 같은 필수 서비스만 제공한다면 어떤 클라우드가 되던지 크게 문제가 없다는 것으로 생각할 수 있다.


매니지드 서비스의 분리


스타트업이나 또는 운영을 자동화하여 개발에 집중하는 조직의 경우 RDS와 같은 클라우드 서비스 제공자가 운영을 대신 해주는 managed 서비스를 이용하는 것을 선호하는데,  근래에 들어서 매니지드 서비스를 전문적으로 제공하는 업체들이 많아졌다. mongoDB나 Redis와 같은 NoSQL의 솔루션을 매니지드 서비스의 형태로 제공하는 compose.io를 보면, 이러한 서비스를 AWS, IBM Softlayer, Digital Ocean등의 몇몇 클라우드 (IaaS)위에서 제공한다는 것이다. 


내가 어떤 IaaS를 사용하건간에, 전문화된 업체를 통해서 특정 솔루션을 매니지드 서비스 형태로 사용이 가능하다. 또 다른 사례중의 하나는 PaaS 플랫폼으로 유명한 Heroku의 경우인데, Heroku는 PaaS 이지만, 사실상 아래 인프라는 AWS로 되어 있다. 현재는 AWS만 지원 하지만, 클라우드 시장이 커감에 따라서 다른 인프라를 충분히 지원이 가능하다고 볼 수 있다. Heroku의 경우 아마존 회사가 아니라 Salesforce.com에 인수되었기 때문에 아마존을 꼭 사용해야 하는 이유가 없다, Cloud Foundary라는 오픈소스를 이용해서 구현이 되었기 때문에 VM만 있다면 큰 문제 없이 다른 인프라에 배포가 가능하다.  (Heroku는 CF를 기반으로 하지 않는다. IBM의 Bluemix가 CF 기반임)





정리해서 말하자면 인프라 클라우드 사업자가 있고 그 위에 매니지드 서비스를 제공하는 전문 사업자들이 점점 더 늘어날 것이고, 이 사업자들은 인프라에 대한 종속성이 없기 때문에, 인프라 클라우드의 차별화가 그다지 크지 않아질 수 있어서 특정 벤더에 대한 종속성이 약해질것이라고 본다.


오픈 API를 통해서 하이브리드 클라우드 기반의 서비스 분산 배치


오픈 소스로 대체가 불가능한 특별한 서비스들이 있는데, AI나 빅데이타에 관련된 것들이 그러하다, 마이크로 소프트나 구글의 경우 머신 러닝 기능을 OPEN API 형태로 제공하고 있고, 알고리즘이 자사의 노하우가 들어가 있는 형태이기 때문에, 다른 오픈소스로 대처가 어렵다 물론 Spark ML과 같은 라이브러리등이 있기는 하지만 개발에 들어가는 노력이나 알고리즘의 품질이 차이가 많이 난다. 얼마전에 구글이 영상 인식을 가능하게 해주는 VISION API를 발표하였고, 마이크로 소프트도 이 보다 많은 기능을 가지고 있는 영상 인식 API를 발표하였다. 흥미로운 점은 이것들이 API로 서비스가 된다는 것이고 이말인 즉, 원격에서 호출이 가능하다는 이야기다. 

이런 API의 특성상 처리 시간이 호출시간에 비해서(네트워크 시간) 길기 때문에, 리모트로 호출한다고 해서 아주 크게 문제가 되지 않고, 근래의 아키텍쳐 특성상 MSA(마이크로 서비스 아키텍쳐)와 같은 분산 서비스 아키텍쳐가 주류를 이루고 있기 때문에, 메인 시스템과 이러한 API 시스템이 꼭 같은 위치에 있지 않더라도 크게 문제가 없다.


클라우드 서비스 제공자 선택은 가격 보다는 부가 서비스와 기술 지원이 관건


Spotify에 사례를 보면 재미있는 것중에 하나가 구글 클라우드를 선택한 주요 이유가 빅데이타 플랫폼과 기술 지원이다.

 Spotify 의 블로그 내용을 보면 가격은 크게 의사 결정 요소로 작용하지 않았다는 것이다. 실제로 요즘 클라우드 시장이 과열이 되면서 디스카운트가 많이 들어가고 있고, 특히 소위 잘나가는 벤더와 잘나가지 못하는 벤더 (조이언트나 랙스페이드 등)가 갈려지면서, 잘 나가지 못하는 벤더들이 레퍼런스를 잡기 위해서 파격적인 할인에 나서고 있다. 클라우드 컴퓨팅의 인프라 가격은 규모의 경제 측면에서 큰 벤더들이 계속해서 시장을 잠식해 나갈 것이고 자체 기술 개발을 통해서 점점 더 가격을 낮춰갈것이다. 아마존의 경우에도 자사의 데이타 센터에 최적화된 CPU를 인텔에 주문했을정도로 이제 인프라 최적화는 점점 더 가속화되어가고 있고, ARM CPU 기반의 서버도 시장에 조금씩 나오는 만큼 가격 경쟁은 가속화 되리라 본다. 특히 통계를 보면 클라우드 가격은 매년 13% 정도씩 감소하고 있다고 한다.


그러면 Spotify가 구글 클라우드 플랫폼을 선택한 이유는 무엇일까?

빅데이타 플랫폼에서 찾을 수 있다. 구글이 경쟁사 대비 더 좋은 빅데이타 플랫폼 서비스를 제공하고 있다는 것인데, AWS의 빅데이타 플랫폼의 하둡이나 스파크, RedShift와 같은 기존의 오픈 소스를 매니지스 서비스로 제공하는 것이 주요 전략이라면, (물론 Dynamo처럼 직접 원천 기술을 만들어서 제공하는 서비스도 있다.) 구글은 기술의 종가답게 이러한 기술들에 대해서 강점을 가지고 있다고 Spotify 블로그에서 전하고 있다.


즉 앞에서 설명한것과 같이 VM 서비스는 평준화 되어 크게 비교 포인트가 되지 못할 것이며, 부가 서비스들 중에서 AI나 빅데이타 영역과 같이 특화되어 대체가 어려운 서비스를 가지고 있는 업체가 강점을 가지게 될것이다.


아울러 기술 지원 부분은 기술 도입에 있어서 중요한데, AWS의 경우 일주일이 멀다하고 계속해서 신기술과 업데이트가 발표되고 있다. 이러한 상황에서 실무 입장에서 새로운 기술을 일일이 찾아보고 자사의 시스템을 클라우드 서비스 제공자에 최적화 하는데는 많은 공부가 필요하고 서비스 제공자에게 서비스 개선등을 요청하기 위해서 원할한 커뮤니케이션 채널이 필요하다. 이를 흔히 프리세일즈(물건을 팔기전에 기술적으로 기술을 설명해주는)와 포스트 세일즈(물건을 판후에, 잘 사용할 수 있도록 지원하는)라고 하는데, 클라우드는 특성상 Self Service의 개념을 가지고 직접 배워서 직접 사용한다는 개념인데, 그러기에는 기술의 속도가 너무 빨라서 이에 대한 지원이 필요하다는 것이다. 실제로 엔터프라이즈 시장에서 성공했던 오라클이나 IBM과 같은 공룡들도 많은 매출이 제품을 판 후에 구현을 도와주는 포스트 세일즈에서 발생을 하였고, 프리세일즈 과정에도 많은 리소스를 투여했던 것이 사실이다.


아직은 클라우드 서비스 제공자의 프리/포스트 세일즈가 강하지는 않지만 (있기는 있다). 이쪽이 성장하면서 좋은 프리/포스트 세일즈 조직을 가진쪽이 비지니스 딜에 좋은 포지션을 가지게 될것이라고 생각해본다.


하이브리드 클라우드 전략


기업의 클라우드 전략을 보면 크게 두가지 갈래로 나뉘어 지는데, 자체 데이타 센터 구축 전략과 클라우드 활용 전략이다.

페이스북과 같은 경우 자체 클라우드를 사용하고, 애플의 경우에도 자체 데이타 센터를 구축하고 있는 것으로 알려지고 있다. http://fortune.com/2016/02/02/apple-data-center-move/

페이스북이나 구글같은 전통적인 테크 기업이면서 서비스 볼륨이 일정 규모 이상되는 경우는 규모의 경제상의 경제상에서 자체 데이타 센터를 구축하고, 자체 서비스에 맞는 인프라를 최적화 해가는 방향으로 집중을 하고 있다. 


반면 Netflix나 Spotify와 같은 서비스 기업은 서비스 개발에 집중을 하고, 인프라는 퍼블릭 클라우드를 사용하는 형태로 방향을 잡아가고 있다. 아무리 인력을 투여해도 퍼블릭 클라우드에서 개발하는 신규 기능을 따라 잡기도 힘들뿐더러, 비용 최적화 면에서도 규모의 경제 특성상 퍼블릭 클라우드가 유리하다는 판단하에서다.





그러면 퍼블릭 클라우드와, 자체 데이타 센터 무엇이 정답일까? 사실은 잘 모르겠다. 

하나 힌트를 얻자면, 애플의 클라우드 전략에서 살펴볼 수 있는데, 애플은 규모의 경제면에서 자체 클라우드를 갖출 정도로 큰 iCloud 서비스를 사용하고 있지만, 자체 클라우드 전략의 이면에서는 데이타 보안에 대한 부분이 있다. 고객의 중요 데이타를 타사의 클라우드에 넣는 것이 계속해서 부담이 되어 왔다. 


그렇다면, 중요 데이타나 중요 시스템은 자사의 클라우드에서 서비스하고, 다른 서비스나 또는 모자른 자원은 퍼블릭 클라우드를 사용하는 하이브리드 클라우드 전략을 갖추지 않을까 조심스럽게 생각해본다.


근래에 얻은 인사이트를 기록해놓고자 정리를 하였지만, 클라우드 컴퓨팅은 이제 거의 필수제가 되어가는것 같다. 특히나 구글,MS,아마존과 같이 규모의 경제를 앞세운 거대 기업들이 이 주도권을 잡아가면서 다른 사업자들은 힘을 잃어가면서 대형 서비스 제공자만 살아 남을것으로 보이고, Digital Ocean과 같은 niche vendor (특정 도메인에 선택과 집중을 통해서 가치를 창출해나가는)들은 특화된 서비스로 특화된 시장을 열어 나갈것이라고 보인다.


서비스 전략이나 시스템 아키텍쳐 설계도 이러한 클라우드 벤더의 변화에 맞춰서 다양화를 해나가야 하지 않을까?

예전 같으면 AWS를 깔고 시스템을 디자인 했다면, 요즘에 다시 시스템을 디자인 한다면 One of IaaS 서비스 + Compose.IO 와 같은 매니지스 서비스 기반의 설계가 조금 더 실용적이 아닐까 생각해본다.