Dev/Architecture

왜 소프트웨어 프로그램 설계 시 MSA를 선택할까? - MSA : MicroService Architecture의 모든 것

린네의 2024. 5. 29. 15:58

 

오늘 포스팅할 주제는 MSA다.  요즘 IT회사에서 채용할 때 우대사항에 항상 들어가 있는 항목이기도 하다. 그렇다면 왜 MSA를 선택할까?

마냥 MSA가 소프트웨어 설계관점에서 베스트일까? 

 

MSA를 자세하기 알아보기 전에, 전통적으로 사용했던 모놀리식에 대해 알아보자.

 

모놀리식 아키텍처(MA:Monolithic Architecture)란?

모놀리식 아키텍처는 애플리케이션 내의 모든 기능과 서비스가 함께 맞물려 단일 유닛으로 운영되는 것을 의미한다.  단일 유닛으로 운영된다는 것은 전체 애플리케이션이 단일 코드로 작성되어 단일 데이터베이스에 연결되는 것이다.

이해하기 쉽게 쿠팡에서 사용했었던 모놀리식 아키텍처 구성도를 가져왔다.

[출처] https://medium.com/coupang-engineering/how-coupang-built-a-microservice-architecture-fd584fff7f2b

 

초기 쿠팡의 서비스는 모놀리식 아키텍처로 구성되어 있었는데, 위 그림과 같이 하나의 웹서버, 하나의 데이터베이스에 모든 서비스 로직 하나로 묶여 돌아가는 형태를 가졌다.

 

아키텍처 구성 방식만 보면 큰 문제가 없어 보인다. 맞다. 서비스 규모가 작다면 해당 모델로도 충분히 안정적인 서비스를 제공할 수 있다.  전통적으로 모놀리식 아키텍처를 사용해 온 것은 분명한 장점이 있기 때문이다.

 

모놀리식 아키텍처가 가지는 장점과 단점은 다음과 같다.

 

  • 장점
  1. 단순성 : 모든 코드가 단일 코드 베이스에 있다. 로컬에서 실행해야 할 경우 단일 애플리케이션만 실행하면 된다.
  2. 간편한 배포 : 단일 애플리케이션으로 구성되어 있기 때문에 간편하게 배포할 수 있다.
  3. 보편성 : 대부분의 개발자가 모놀리식 아키텍처에서 작업한 경험이 있어 프로젝트를 쉽게 시작할 수 있다.
  4. 디버깅이 쉬움 : 모든 코드가 단일 애플리케이션에 있어 디버깅이 쉽다.
  5. 쉬운 테스트 : 디버깅과 마찬가지로 모든 코드가 단일 애플리케이션에 있어 테스트 수행이 쉽다.
  6. 쉬운 모니터 장점 : 코드가 모두 단일 프로젝트에 존재하여 오류 시 문제가 발생한 위치를 식별하기 쉽다. 

 

  • 단점
  1. 규모가 큰 서비스에서 유지보수가 어려움 : 시간이 지남에 따라 애플리케이션이 커지면 관리가 어렵다. 관심사의 분리도 쉽지 않다. 
  2. 유연하지 않은 확장성 : 애플리케이션 확장시 전체 애플리케이션 단위로 확장해야 한다.
  3. 대규모 팀 작업이 어려움 : 모든 팀이 동일한 코드와 동일한 프로젝트에서 작업하기 때문에 코드 병합에 대한 충돌 가능성이 높고 기능 변경 시 다른 팀이 작업에 영향을 줄 수 있다. 또한 테스트와 배포 시 대기 시간이 증가할 수밖에 없다.
  4. 기술 사용 제한 : 모든 애플리케이션이 통합적으로 돌아가므로 부분적으로 다른 기술을 적용하기 쉽지 않다.
  5. 부분 장애가 서비스 전체 장애로 이어짐  : 개발자가 잘못된 코드를 배포하거나 트래픽 증가가 있을 경우 부분 서비스의 장애가 전체 서비스 장애로 확대됨 

 서비스를 처음 기획할 때는 크게 문제가 없다. 그러나 애플리케이션이 운영되는 이상 추가되거나 개선되는 일은 반드시 일어난다. 애플리케이션이 추가되고 개선될 때마다 아키텍처는 더 복잡해진다. 애플리케이션 내 하나의 프로세스가 확장되어야 할 때 전체 애플리케이션도 확장되어야 하며, 단일 기능을 최적화하기는 더더욱 어려워진다.  확장되는 서비스에서 모놀리식 아키텍처가 가지는 단점은 두드러질 수밖에 없다.

 

이러한 모놀리식 아키텍처의 단점을 개선하기 위해 제안된 것이 마이크로서비스아키텍처이다.

 

 

 

마이크로서비스 아키텍처(MSA:Microservice Architecture)란?

마이크로서비스 아키텍처는 모놀리식 아키텍처와 달리 자유도가 높은 소프트웨어 프로그램 디자인 방법론으로 복잡성이 낮은 기능들을 제공하는 독립적인 서비스 여러개를 느슨하게 결합하고 네트워크를 통해 서비스들끼리 통신하게 만들어 하나의 서비스를 구성해 내는 아키텍처이다.

 

 

 

[출처] https://medium.com/coupang-engineering/how-coupang-built-a-microservice-architecture-fd584fff7f2b



위 그림은 모놀리식으로 구성되어 있던 서비스를 마이크로서비스로 바꾼 결과이다. 하나의 애플리케이션으로 묶여 있던 Front, Order, Payment, Delivery 등을 각각의 마이크로서비스로 분리했다. 이렇게 MSA를 사용함으로써 얻을 수 있는 장점은 다음과 같다.

 

  • 장점
  1. 유연한 확장 : 각 마이크로서비스는 다른 서비스와 독립적으로 확장할 수 있다. 주문 서비스에 대해 확장이 필요할 경우, 전체 애플리케이션을 확장하는 대신 주문이라는 특정 마이크로서비스만 지정해서 확장이 가능하다.
  2. 독립적인 배포 : 마이크로서비스는 느슨하게 결합되어 있으므로 하나의 마이크로서비스만 지정하여 배포할 수 있다. 부분적으로 배포가 가능하게 되므로, 전체 애플리케이션을 중지할 필요가 없다.
  3. 단일 실패 지점 제거 : 애플리케이션을 여러 소규모 서비스로 분할하여, 전체에 영향을 미치는 단일 실패 지점을 제거한다.
  4. 전체 서비스 중단 위험 감소 :  특정 마이크로서비스가 중단되더라도 전체 애플리케이션에 영향을 미치지 않고 해당 마이크로서비스에만 영향을 미친다.
  5. 다른 데이터베이스를 소유 : 각 마이크로서비스별로 데이터베이스를 소유할 수 있다. 따라서 서비스 별로 최적의 데이터베이스를 선택할 수 있다.
  6. 다양한 기술 수용 가능 : 각 마이크로서비스는 서로 다른 기술을 가질 수 있다. 가령, 서비스별로 선택하는 언어를 완전히 다르게 구성하는 것도 가능하다. 

MSA가 가진 장점으로 모놀리식이 가지는 단점을 해결할 수 있다. 하지만 MSA가 모든 애플리케이션 설계의 정답인 것은 아니다.  MSA도 단점을 가지고 있다.

 

  • 단점
  1. 개발 생산성 필요 : 여러 개의 마이크로서비스 중 하나에 새로운 기능을 구현해야 할 때, 다른 서비스에 접근할 수 있도록 로컬에서 많은 애플리케이션을 실행할 수 있는 환경이 필요하다.
  2. 디버깅이 어려움 : 디버깅하거나 테스트를 위해 둘 이상의 마이크로서비스의 실행이 필요하므로 복잡하다.
  3. 마이크로서비스 간 통신 : 동기/비동기 방식의 통신을 고려해야 하며, 이런 부분이 애플리케이션의 복잡성을 증가시킨다.
  4. 표준화 부족 : 공통 플랫폼이 없어 여러 언어, 로깅 표준 및 모니터링이 복합적으로 사용될 수 있다. 

 

MSA는 제공되는 서비스를 분산해야 하기 때문에, 잘못 분해할 경우 모놀로 식에서 단점만 부각된 분산 모놀리식이 될 수 있기 때문에 도입 시점을 신중하게 고려해야 한다. 제공하려는 서비스 규모가 작다면, 굳이 MSA를 도입할 필요는 없다. 개발해야 하는 인력과 시간이 부족한데 무턱대고 MSA를 사용하면 오히려 개발속도 저하만 이끌어 내는 꼴이 될 수 있다는 것을 염두에 두어야 한다. 

 

소프트웨어 아키텍처를 적용하기 전에, 팀이 개발하고 있는 애플리케이션이 크고 복잡해질 가능성이 있는지, 도메인이 MSA와 적합한지, 가용성과 확장성이 필요한지에 대해 심도 깊은 분석이 반드시 선행되어야 한다.

 

 

MSA에서  엔드 포인트 통합하기 

마이크로서비스는 각 서비스가 다른 서버에 분리되어 배포된다. 따라서 API의 엔드포인트, 즉 서버의 URL이 모두 다르다!  서로 다른 URL을 사용하기에는 불편함이 따른다. 이를 해결하기 위한 방안으로 API Gateway가 있다.

 

  • API Gateway

마이크로 서비스 아키텍처 설계에서 가장 많이 언급되는 컴포넌트 중에 하나로, 마치 프락시 서버처럼 API 앞에서 모든 API에 대한 엔드 포인트를 통합하고 몇 가지 추가적인 기능을 제공하는 미들웨어다. 중앙에 서비스 버스와 같은 역할을 하는 채널을 배치시켜서 전체 토폴로지를 Hub & Spoke 방식으로 변화시켜 서비스 간 호출을 단순화시킬 수 있다. 쉽게 말하면 EdgeServer로 모든 API의 EndPoint를 받아서 내부의 마이크로 서비스로 각각 라우팅 해주는 역할을 한다.

 

[출처] https://dongwooklee96.github.io/post/2021/03/27/soa-%EB%AA%A8%EB%86%80%EB%A6%AC%ED%8B%B1-%EA%B7%B8%EB%A6%AC%EA%B3%A0-msa-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98.html

 

더보기

cf. Hub & Spoke 방식

 

[출처] https://learn.microsoft.com/ko-kr/azure/cloud-adoption-framework/ready/azure-best-practices/hub-spoke-network-topology



 

이러한 API Gateway는 다음과 같은 역할을 수행한다.

 

  • 오케스트레이션 (Orchestration)

여러 개의 서비스를 묶어서 하나의 새로운 서비스를 만드는 개념이다. 예를 들어 주문과 프로모션적용이라는 서비스가 있을 때, 이 두 개의 서비스를 묶어서 프로모션이 적용된 주문이라는 새로운 서비스를 도출할 수 있다.

 

  • 공통 기능 처리 (Cross Cutting Function Handling)

API에 대한 인증이나 로깅과 같은 공통 기능에 대해서 서비스 컴포넌트 별로 중복 개발해야 하는 비효율성을 유발할 수 있다. 이러한 공통 기능을 API Gateway에 할당하여 API자체는 비즈니스 로직에만 집중하여 개발 중에 발생할 수 있는 중복을 방지한다.

 

  • 중재(Mediation)

네이티브 메시지 포맷을 JSON으로 상호 변환해 주는 메시지 변환 기능이나 프로토콜을 변환하는 기능, 서비스 간의 메시지를 라우팅 해주는 여러 가지 고급 중재 기능을 제공한다. 마냥 다 쓰는 게 좋은 것은 아니니 이 또한 고도화된 설계와 기술적 경험이 있을 때 사용하는 것을 권장한다.

 

 

MSA에서 서비스 간 트랜잭션 처리 

MSA를 도입하면 가장 크게 겪는 문제 중에 하나가 DB의 ACID이다. 예를 들어 상품을 주문하고(service1), 주문한 상품에 대한 재고를 업데이트(service2)할 때 오류가 발생한다면 정상적으로 주문된 서비스에 대한(service1) 처리를 어떻게 해야 할지가 난감해진다.

 

 

더보기

cf. 데이터베이스의 ACID 

1. 원자성 (Atomicity) : 트랜잭션은 모두 성공하거나 모두 실패한다.

2. 일관성 (Consistency) : 트랜잭션이 끝난 후 데이터베이스는 일관된 상태를 유지해야 한다.

3. 격리성 (Isolation) : 트랜잭션은 다른 트랜잭션과 독립적으로 실행되어야 한다.

4. 지속성 (Durability) : 트랜잭션이 성공했을 경우 그 결과는 영구적으로 반영되어야 한다. 

 

 

이럴 경우 고려되는 해결 방안으로 2 Phase Commit과 SAGA Pattern이 있다.

 

  • 2PC(2-Phase-Commit)

일반적인 싱글 노드 트랜잭션에 존재하지 않는 새로운 컴포넌트인 트랜잭션 매니저(코디네이터)를 사용한다.  간단하게 말하면 트랜잭션을 각 DB마다 실행되도록 구성하고, 해당 트랜잭션이 read, write, lock, unlock 등의 동작을 수행할 동안 최종적으로 이를 커밋할지에 대해 코디네이터가 결정하도록 위임한다.

 

즉, 복수의 db에 대해 해당 트랜잭션을 수행하고 모든 db에서 성공적으로 실행되었는지 체크하는 phase1, 이를 최종적으로 적용되게 하는 phase2로 구분된다. 따라서 Two Phase Commit이라고 표현하는 것이다. 

 

[출처] https://velog.io/@jungbumwoo/Two-Phase-commit-%EC%9D%B4%EB%9E%80-2PC

 

 

해당 패턴의 문제점은 서비스가 증가할수록 시스템의 대기시간이 길어지게 되고 응답시간의 증가를 초래한다는 것이다. 기본적으로 분산 트랜잭션 형태이므로 분산 트랜잭션을 지원하지 않는 NoSQL에서는 지원하지 않고 이종 간의 DB에서 구현이 까다롭다. 따라서 MSA는 그다지 적합하지 않은 패턴이다. 이에 대한 대안으로 Saga Pttern이 등장했다.

 

 

  • Choreography SAGA

하나의 큰 트랜잭션으로 묶지 않고 각 서비스의 작업을 트랜잭션 단위로 처리한다. 각 서비스의 이벤트에 의해서 처리된다.  각각의 서비스가 자신의 local 트랜잭션을 관리하고, 각 로컬 트랜잭션이 종료되면 완료 event를 발생시켜 다음 실행되어야 할 애플리케이션에 전달한다. 완료 event를 수신한 애플리케이션은 이벤트에 발생여부에 따라 다음 작업을 처리하게 된다.  

[출처] https://dongwooklee96.github.io/post/2021/03/27/soa-%EB%AA%A8%EB%86%80%EB%A6%AC%ED%8B%B1-%EA%B7%B8%EB%A6%AC%EA%B3%A0-msa-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98.html

 

 

 

  • Orchestrator SAGA

이벤트를 통해서가 아니라 각 서비스를 관리하는 Orchestration 클래스가 직접 처리하는 방식으로, 메시지 이벤트를 사용하지 않고 동기식 API를 사용한다.  중앙에서 컨트롤하는 매니저(Orchestration 클래스)가 있어 복잡성이 줄고 구현과 테스트가 쉽지만 매니저 자체를 추가해야 하는 단점을 가진다.

[출처] https://dongwooklee96.github.io/post/2021/03/27/soa-%EB%AA%A8%EB%86%80%EB%A6%AC%ED%8B%B1-%EA%B7%B8%EB%A6%AC%EA%B3%A0-msa-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98.html

 

 

 

 

번외: 서비스 지향 아키텍처(SOA:Service Oriented Architecture)

MSA 하면 따라오는 게 SOA(Service Oriented Architecture, 서비스 지향 아키텍처)인데 둘 다 복잡한 애플리케이션을 작업하기 쉬운 작은 구성 요소들로 세분화한다는 점에서 유사하다. 

 

  • SOA

서비스 단위로 개발하고, 개발된 서비스들을 공유함으로써 재가용성을 늘리고 유연성을 확보한다. SOA의 목표 중 하나는 결합도에 대한 걱정 없이 컴포넌트를 재사용하는 것에 있다. ESB(Enterprise Service Bus)를 통해서 서비스 사이 동기화가 일어난다. ESB는 서로 다른 애플리케이션 간의 실시간 데이터 교환을 지원하는 소프트웨어 아키텍처 패턴이다. ESB를 사용해서 데이터 변환, 프로토콜 변환, 메시지 라우팅과 같은 작업을 수행하여 애플리케이션 통합을 쉽게 진행할 수 있다. 애플리케이션이 실행될 때 관련 데이터를  ESB에 전달하고, ESB는 데이터를 변환하여 다른 애플리케이션으로 전달하는 식이다. 

 

 

[출처] https://dongwooklee96.github.io/post/2021/03/27/soa-%EB%AA%A8%EB%86%80%EB%A6%AC%ED%8B%B1-%EA%B7%B8%EB%A6%AC%EA%B3%A0-msa-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98.html

 

 

 

  • MSA와 SOA의 차이점

 SOA서비스는 완전한 비즈니스 기능을 제공하지만 각 마이크로서비스는 단일 작업에만 특화된 훨씬 작은 소프트웨어 구성 요소이다. 

둘의 가장 큰 차이점은 범위에 있다. SOA가 전사적(enterprise)인 아키텍처 접근 방식이라면, 마이크로 서비스는 애플리케이션 개발 팀의 구현 전략이다.

 

 

  SOA MSA
구현 리소스를 공유하는 다양한 서비스 독립적인 목적별 소규모 서비스
통신 ESB는 SOAP, AMQP, MSMQ와 같은 메시징 프로토콜 사용 API, Java 메시지 서비스, Pub/Sub
데이터 스토리지 공유 데이터 스토리지 독립 데이터 스토리지
배포 과제, 작은 변경 사항에도 전체 재구축이 요구 됨 용이한 배포. 각 마이크로서비스를 컨테이너화할 수 있음
재사용성 공유 공통 리소스를 통해 서비스를 재사용할 수 있음 모든 서비스에는 고유한 독립 리소스가 있음. API를 통해 MSA를 재사용할 수 있음
속도 서비스가 더 많이 추가될수록 속도의 저하 발생 트래픽이 증가하더라도 일정한 속도 보장
거버넌스 유연성 모든 서비스에 걸쳐 일관된 데이터 거버넌스 적용 각 스토리지별로 다양한 데이터 거버넌스 정책

 

더보기

cf. 데이터 거버넌스란?

데이터의 보안, 개인정보 보호, 정확성, 가용성, 사용성을 보장하기 위해 수행하는 모든 작업을 가리킨다. 사람이 취해야 하는 조치와 따라야 하는 프로세스, 데이터의 전체 수명 주기 동안 이를 지원하는 기술들이 포함된다.

 

 

 

'Dev > Architecture' 카테고리의 다른 글

헥사고날 아키텍처(Hexagonal Architecture) 쉽게 알기  (0) 2024.05.29