Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA) 보고난뒤….(MSA<>Monolith)

2023. 4. 21. 11:20개인노트

반응형

많은 회사들이 MSA(MicroService Architecture)의 형태로 변경되어가고 있고 그에 따른 궁금점들이 많았다.

내가 일 했던 회사들의 경우 그 규모가 크지 않았기 때문에 보통의 경우 모놀리스(Monolith) 형태의 어플리케이션 이였기 때문이다.

조금씩 공부하다보니 모놀리스와 MSA 무엇이 더 좋다 나쁘다 이런게 아닌 상황에 따른 선택이 맞지않나 싶다.(로컬환경에서 해당 강의를 보면서 MSA환경에서 테스트를위해 user, order, catalog,eureka, gateway, kafka 등등 프로그램을 몇개를 실행 하였는지..모르겠다.... ㅠㅠㅠ )

기본적인 개념을 잡고싶어서 인프런에서 Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA) 강의를 구매하였고 새로운 지식들에 접근 하게되어 재밌었다..!

기본적으로 모놀리스와 MSA의 차이점이란 무엇인가 살펴보게되면 아래와 같다.

하나에서 모든걸 처리 할 수 있도록 가지고 있던가 아니면 그걸 특정 단위로 나뉘어져 각각의 독립적인 어플리케이션 또는 크게는 서로 다른 DB, 개발언어 등등 서로에 대해서 크게 간섭이 없는 형태로 볼 수 있다.

모놀리스와 MSA

모놀리스 형태에서는 하나에서 모두 처리하기 때문에 사용자가 Java로 개발되었다면 당연히 주문도 동일한 언어 및 환경에서 개발되어야 한다.

그러나 MSA환경에서는 사용자가 Java로 되어있다고 주문을 담당하는 어플리케이션이 동일하게 개발되어야 하거나 그런게 아니다.
만약 채팅서버가 추가된다고 했을때 NoSQL을 사용하여 개발하는게 주로 보이는데 이 경우에는 모놀리스 구조에서 사용하고자 할 때 불편한점이 많이 발생하게된다. 그리고 사용자, 주문, 카테고리에서는 필요하지않는 관련 라이브러리를 가지게 될 수 있다. 멀티모듈 형태로 구성하게되면 각각의 서로다른 라이브러리 관리를 할 수도 있지만 결국 그 종류가 많아지고 크기가 커 질 수록 MSA환경을 고려하게 되는듯 하다.

처음 MSA라는 걸 알게 되면 궁금한점이 있었던 부분은 다음과 같았다.

  1. 사용자가 특정 상품에 대해서 주문을 하기 위해서는 그럼 각각 API호출을 통한 통신을 하게되는건가? 다른방법은 없나??
  2. 사용자가 주문을 많이하여 주문 어플리케이션을 여러개를 띄워 스케일아웃 하게되었을때.. 어떤식으로 편하게 할 수 있는건가? (이 경우에는 보통 크기가 작은 환경의 경우 Nginx에 특정 어플리케이션을 올리고 port번호를 맞춰주는 등등 여러가지 수정에 손이가는게 많았다.)
  3. API호출이 잘 안되거나… 문제가 있을 때 어디에 어떻게 문제가 있는지 모니터링이나 추적은 어떤방식으로 하는거지..?(Zipkin, Sleuth 사용)

위 상황들에 대해서 여러가지 기능을 적용해주는게 Spring Cloud 였다.

강의에서 사용하는 기본적인 틀은 아래와 같았다.

넷플릭스에서 제공한 라이브러리 Spring Cloud Eureka를 사용하여 관련된 서비스들에 대한 정보를 편리하게 관리해주고 Spring Cloud Gateway 서버를 통해 해당부분들을 컨트롤 하는 것이였다.

Gateway서비스는 각각 서비스에 대한 정보를 유레카 서버로 부터 받아와서 연결 할 수 있는 형태였다.

구성도

여기서 또 고민이 되던부분은 Gateway서버가 아무리 튼튼하고 좋은걸 사용하더라도… 음 만약 사용자가 감당할 수 없을 만큼 많아진다면 모든 사용자의 요청을 다 처리하는 Gateway서버를 구성 할 수 있을까..? 의문이였다.

참고하면 좋은 MSA의 영상으로는 https://www.youtube.com/watch?v=J-VP0WFEQsY 을 보면 좋을듯 하다.

4년전 영상이긴 하지만 11번가에서 MSA 환경으로 변경을 하면서 적용하면서 고민했던 부분과 서로간의 통신을 어떤 방식으로 처리 할지에 대한 여러가지 생각들이 보였다..!

해당영상에서는 Ribbon을 사용했지만 Eureka로 대체되었고, 서킷브레이커를 적용하는부분도 Hystrix에서 Resilience4j로 대체 적용 된듯하다.

https://spring.io/blog/2018/12/12/spring-cloud-greenwich-rc1-available-now

 

Spring | Home

Cloud Your code, any cloud—we’ve got you covered. Connect and scale your services, whatever your platform.

spring.io

실제로 적혀있는 대체 라이브러리 표

Replacements

We recommend the following as replacements for the functionality provided by these modules.

Current Replacement

Hystrix Resilience4J
Hystrix Dashboard / Turbine Micrometer + Monitoring System 
Ribbon Spring Cloud Loadbalancer
Zuul 1 Spring Cloud Gateway
Archaius 1 Spring Boot external config + Spring Cloud Config

 

서킷브레이커란..?

주식에서 사용되는 용어와 비슷한 개념으로 볼 수 있을 듯 하다. (주식시장에서 가격이 급격히 떨어지는 경우에 반응하여, 시장을 진정시키기 위해 매매를 일시적으로 정지시키는 것을 말한다.)

개발자의 입장에서는 API요청에 문제가 생겼을때 안되는걸 알면서도 해당 서비스에 요청이 들어가게되면 정상적으로 동작하지 않는 프로세스에 리소스가 낭비되게되고 다른데에도 영향이 있을 수 있다. 그에따라 서킷브레이커에서 설정된 시간, 확률 등으로 조절 할 수 있게된다.(예를들어 10건중 50%가 실패한다면 특정 시간동안은 요청하지 않고 무시한다던지 하는..?)

 

MSA환경에서 각각 서비스를 호출 할 때 RestTemplate을 통하여 통신을 할수도 있고, Feign Client를 사용하여 Eureka서버에 설정된 서비스 이름으로 편하게 통신연결이 가능하기도 하다.

아래는 사용된 짧은 예시…

@FeignClient(name = "order-service")
public interface OrderServiceClient {

    @GetMapping("/order-service/{userId}/orders")
    List<ResponseOrder> getOrders(@PathVariable("userId") String userId);
}

그러나 위 방식도 각각의 서비스가 많아지고, 복잡해지면 힘들 수 있다.

해당서비스에 대해서 잘 알아야하고… 아마 연동을 위한 규격서(문서)가 자세하지 않다면 직접 해당 주소에 대한 정보를 확인 할 수 있어야 제대로된 요청을 할 수 있을 듯 하다.

Feign Client를 사용한 모습은 11번가 영상의 대략 36분의 시간대를 확인해보면 될 듯하다.

마지막으로…

각각 분리된 상태로써 존재하기 때문에 모놀리스 구조에서 생각하는대로 트랜잭션이 처리되지 않는다는 점을 고려해야한다…

비즈니스 로직 구성

  1. 사용자가 주문한다.
  2. 주문서비스에서 해당 주문을 처리하기 위해 카테고리 재고가 있는지 확인한다.
  3. 재고가 없다면 롤백 OR 실패처리한다.
  4. 재고가 있다면 정상처리.

위와 같이 플로가 흐른다고 하였을 때 하나에서 동작하는 모놀리스 구조에서는 그냥 비즈니스 로직상에서 트랜잭션을 하나로 잡은 뒤 필요한 정보들을 확인 후 처리하는 로직을 작성하면된다.

그러나 MSA 환경에서는….?

  1. 사용자는 주문요청 API를 날린다.
  2. 주문은 카테고리 재고 확인 요청을 한다.
  3. 카테고리는 재고정보를 전달한다.
  4. 주문은 재고정보를 확인 후 처리한다.
  5. 주문은 사용자에 주문요청 응답을 한다.

겉보기에는 아무런 문제가 없어보이지만…

여러명이서 한정적인 재고를 요청하였다면…….?

주문과 카테고리는 각각 다른DB를 사용하고 트랜잭션의 격리된 환경을 보장 할 수 없다…….…

그리고 내가 본 강의에서는 메시징 서비스(Kafka or RibbitMQ)를 중간에 두는 경우가를 설명하였다.호출이 아닌 메시징 서비스를 거쳐서 각각 독립적으로 동작하는것이다.

주문을 하면 바로 성공하는것이 아닌 보류상태(Pending)로 처리하고, Kafka의 Topic에 값을 넣는다.

카테고리에서는 메시징큐에 있는 값을 읽어 재고를 확인 후 차감처리한다. 재고가 없다면 거절을 보낸다.

그리고 그에 대한 응답을 Kafka에 다시 보낸다.

위와 같은 방식을 보상트랜잭션이라고 하는듯 하다…!

이러한 방식을 Saga Patten 이라고 하는듯 하니.. 여러가지 또 공부해야 할게 생겼다..!

반응형