MSA(Micro Service Architecture)란 ?

시스템을 여러개의 독립된 서비스(기능)로 나눠서, 이 서비스를 조합함으로서 기능을 제공하는 아키텍처 디자인 패턴입니다. 완전히 독립적으로 배포가 가능하기 때문에 다른 기술 스택을 사용할 수 있어요.

모놀리식 구조(Monolithic Architecure)

하나의 프로그램안에 모든 기능이 있는 통합되어 있는 형태를 말합니다. 관리가 쉬우며 초기 배포 단계에 설정할 것이 많지 않아서 MSA 보다 비교적 간단하게 서버 운영이 가능합니다. :)

모놀리식 구조 문제점

  • 부분 장애가 전체 서비스 장애로 이어진다.

    모놀리식 구조를 가진 프로젝트를 했을 당시, 회원 가입 로직에서 문제가 생겨 서버가 다운된 적이 있습니다. 개발자의 잘못된 코드 혹은 갑자기 트래픽 증가로 인해서 성능에 문제가 생겼을 때, 서비스 전체의 장애로 확대될 수 있어요.

  • 부분적인 scale-out 이 어렵다.

    회원 가입은 부하가 자주 일어나지 않지만, 상품 주문은 빈번히 일어나는 작업이죠! 이럴 경우 더 많은 트래픽을 감당할 수 있는 인프라 구조가 필요한데요. 모놀리식 구조의 경우 서버를 나누어 처리할 수 없기 때문에 부분적인 스케일 관리가 어렵습니다.

  • 서비스의 변경이 어렵고, 수정시 장애의 영향 파악이 어렵다.

    여러 기능이 하나의 프로젝트 내부에 있다보면 의존성이 강하게 엮어있어서 장애 포인트를 찾기 어려웠던 경험이 있어요. 그래서 이런 부분을 조영호님의 우아한 객체지향 영상을 보며 조금이나마 해소하고자 했었는데요. 이런 문제가 발생하는 이유는 하나의 프로젝트에 여러 기능들이 있기 때문이기에 MSA 로 전환한다면 해당 문제를 조금이나마 해소할 수 있을 거에요.

  • 배포 시간이 오래걸린다.

    작은 기능임에도 불구하고 프로젝트 규모가 커 테스트 실행시간, 배포 시간이 많이 드는 경험을 한 적이 있어요. 기능별로 분리하면 테스트 코드 개수도 감소하고, 배포 파일 크기도 감소하기 때문에 CI/CD 속도도 훨씬 빨라질거예요!

MSA 등장 배경

이러한 모놀리식 구조의 문제점들을 보완하기 위해 MSA가 등장하게 되었답니다. 기존에 특정 물리 서버에 서비스를 올리던 on-promise 서버 기반의 모놀리식에서 이제는 클라우드 환경을 이용하여 서버를 구성하는 MSA 로 많은 서비스들이 전환되고 있어요.

MSA 특징

API 를 통해서만 상호작용을 할 수 있어요. 서비스 끼리 end-point 를 API 형태로 외부에 노출하고, 실질적인 세부 사항은 모두 추상화 합니다.

  • 하나의 기능만 수행합니다. 여러 어플리케이션에서 서비스를 호출하여 상호작용할 수 있습니다.
  • 프로토콜을 사용해 통신하므로 서비스 구현 기술을 다양하게 사용할 수 있습니다.
  • 집중화된 관리 체계를 사용하지 않아요. ESB(Enterprise Sevice Bus)와 같은 무거운 제품에 의존하지 않고, REST 등 가벼운 통신 아키텍처, 또는 카프카 등을 이용한 메세지 스트림을 주로 사용합니다.
  • 독립적인 배포가 가능해요!
  • 개별적인 scale-out 이 가능해요. 메모리, CPU적으로도 상당부분 이득이 됩니다.

MAS 단점

  • 많이 복잡해요. 서비스가 분산되어 있기 때문에 내부 서비스 통신을 어떻게 가져가야할지 정해야하고, 또 통신 장에나 서버 부하가 있을 경우 트랜잭션 관리에 대해서도 고민할 점이 많아요.

    모놀리식에서는 단일 트랜잭션을 유지하면 됐지만, MSA 에서는 비지니스에 대한 DB 를 가지고 있는 서비스도 각기 다르고 서비스 연결을 위해서는 통신이 포함되기 때문에 트랜잭션을 유지하는게 어렵습니다.

  • 통합테스트가 어렵다. 개발 환경과 실제 운영환경을 동일하게 가져가는 것이 쉽지 않아요.

  • 단일 서비스를 배포하더라도, 다른 서비스들과 연계가 정상적으로 이뤄지고 있는지도 확인해야합니다.

모놀리식 vs MSA

다양한 기술 스택을 사용하고, 메모리 관리가 용이하고, 단일 장애가 전체 시스템에 영향을 주면 안되는 상황들은 보통 대규모 서비스를 운영할 때 필요할 것 같아요. 보통 서비스 유저가 1000명 정도 되는 서비스에서는 MSA 의 장점을 취하지 충분히 운영이 가능했었거든요. 서비스가 점점 커지면 각 도메인간 의존성이 늘어나고, PR 단위에서 많은 충돌이 발생하고, 배포하는데도 오래걸렸던 경험이 있어요. 이런 문제들을 해소하기 위한 방법 중 하나인 MSA 를 학습하며 사용자가 많은 서비스를 운영해보면서 더 많은 고민들을 하면 재밌겠다고 생각하게 된 계기가 되었습니다.

MSA 에서 궁금한 점들

어떻게 트랜잭션 관리를 할까?

    배달 시스템에서 주문을 한다고 가정하면 
    - `결제를 시작하고`
    - `쿠폰을 적용하고`
    - `카드를 선택하고`
    - `메뉴 주문이 가능한지 한번더 확인`
    - `결제 완료`
    - 배달 요청이 전송된다.
이 여러개의 작업 단위를 하나의 트랜잭션으로 묶어서 하나라도 제대로 된 처리가 되지 않으면 롤백하고 예외 처리를 해줘야하는데 이런 부분을 어떻게 하고 있을까?

그동안 서비스 레이어를 작성하면서 API 요청은 하나만 들어오고 여러개의 행위를 수행했는데 이렇게 되면 
    
    1)  결제를 시작한다. (api call)
    
    2) 쿠폰 사용가능한지 확인한다. 
    
    2-1) 쿠폰 사용이 가능하면 사용 처리한다.
    
    3) 쿠폰 적용한 금액을 반환한다.
    
    4) 카드를 선택한다.
    
    5) 결제팀에서 결제 요청을 전송한다.
    
    A- 1) `결제가 취소`되었다.
    
    A-2) 결제가 실패되면 `쿠폰사용도 취소`한다 . 
    
    ---
    
    B-1) `결제가 성공`했다.
    
    B-2) `결제 내역을 히스토리에 저장`한다.

이런 느낌으로 트랜잭션이 묶여야 할 것 같은데 이런걸 이벤트 처리로 하는건지 아직 이벤트에 대한 학습이 부족해서 잘 모르겠네요 ㅠㅠ 이 부분은 추가학습 한 뒤 내용을 덧붙여보겠습니다.

모놀리식 vs MSA

시스템의 규모가 작음에도 MSA 구조를 사용하는 것은 모든 요청마다 네트워크 비용이 추가되고, 서버 운영 비용도 추가되고, 테스트를 하기 어려워지고, 트랜잭션관리도 하기 힘들어지는 문제를 야기할 수 있어요. 그래서 대부분의 개발초기에서는 모놀리식 구조를 가지고 있다가 서비스가 커지면 MSA 전환을 고려하는 것 같아요 ㅎㅎ 각 구조의 트레이드 오프를 이해하고 사용해야겠습니다.

참고