MSA에 대한 고찰 (1)

들어가며

서버, 백엔드 공부를 하다보면 누구나 MSA라는 아키텍쳐를 들어봤을 것이다. 필자 또한 MSA라는 아키텍쳐에 대해 알고는 있지만, 아직은 모놀리틱(monolithic)하기만 해도 충분한 정도의 트래픽만을 마주해보았기 때문에 일단은 관심만 가지고 있는 상황이었다. 그러던 중 wikidocs에서 속성 스프링 클라우드와 서비스 메시 라는 잘 짜여진 docs를 보고 이 글들을 차근차근 따라간다면 최소한 MSA 아키텍쳐로의 전환에 대한 이유를 이해할 수 있을 것 같아 블로그와 github에 정리하기로 결정했다.

또한 어플리케이션을 개발할 때 구현복잡도와 운영복잡도로 나뉜다고 생각하는데, 기존에 MSA 아키텍쳐는 구현복잡도와 운영복잡도 모두 매우 높아 접근할 생각조차 못했지만 지금은 LLM으로 인해 구현복잡도가 많이 내려왔다고 생각하여 최적의 타이밍이라고 생각했다.

MSA(Micro Service Architecture)란?

In short, the microservice architectural style is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API. These services are built around business capabilities and independently deployable by fully automated deployment machinery. There is a bare minimum of centralized management of these services, which may be written in different programming languages and use different data storage technologies. – James Lewis and Martin Fowler (2014)

James Lewis and Martin Fowler는 다음과 같이 MSA를 처음으로 정의했다. 즉 하나의 큰 어플리케이션을 작은 서비스의 모음으로 쪼개 중앙 집중식 관리를 최소화하여 서로간 경량 프로토콜을로 장애를 격리시키는 아키텍쳐를 말한다.

MSA 전환의 의의

먼저 기존의 모놀리틱한 서비스는 오랜 시간동안 주된 개발 방식이었다. 모든 기능이 하나의 어플리케이션 안에 담겨있어 개발과 배포가 단순하다는 장점이 있지만 시간이 지나면 지날수록, 기술이 발전하면 발전할 수록 요구사항의 복잡성이 높아져 유지보수와 확장이 어려워진다는 한계점이 명확하다. 또한 기술 스택에 제한이 있고 스택에 종속되기 쉬워 새로운 기술의 도입이 어렵다는 단점도 있다. 마지막으로 하나의 컴포넌트에서 문제가 발생했을 때 같은 어플리케이션 내부 전체적으로 문제가 전이 될 수 있다는 한계도 있다.

그렇다면 모놀리틱한 서비스에서 MSA로 전환하면 어떤 효용이 있을까? 효용을 알아보기 전에 현대적 백엔드 아키텍쳐의 구성 요소 및 요건 부터 알아보자.

현대 백엔드 아키텍처의 자격 요건

과거의 아키텍쳐가 기능 구현에 집중했다면, 현대의 클라우드 네이티브 아키텍쳐는 다음 세 가지를 필수 자격 요건으로 요구한다.

1. 확장성 (Scalability)

먼저 서버를 확장가능성이다. 확장 가능성은 수직 확장 (Scale-Up), 수평 확장 (Scale-Out)으로 나뉜다.

  1. 수직 확장 (Scale-Up) 기존 서버의 CPU나 메모리를 증설하는 방식이다. 간단하지만, 물리적인 한계가 명확하고 비용이 기하급수적으로 증가한다. 모놀리스 아키텍처가 주로 선택하는 방식이다.

  2. 수평 확장 (Scale-Out) 동일한 애플리케이션을 실행하는 서버의 ‘대수’를 늘리는 방식이다. 클라우드 환경의 핵심이며, 사실상 무한대에 가까운 확장이 가능하다. MSA는 ‘수평 확장’을 극단적으로 추구하는 아키텍처다. ‘주문’ 서비스에 트래픽이 몰리면 ‘주문’ 서비스만 독립적으로 100대로 늘리고, 상대적으로 트래픽이 적은 ‘회원’ 서비스는 3대만 유지하는 식의 유연한 대응이 가능하다.

2. 탄력성 (Resilience)

과거엔 장애가 발생하지 않는 ‘Fail-safe’한 시스템을 목표로 했다고 한다. 하지만 수백, 수천 개의 분산된 서비스로 구성된 MSA에서는 장애를 예외가 아니라 일상으로 가정하고 개발한다. 즉 현대 아키텍쳐는 장애가 발생하더라도 전체 서비스가 중단되지 않는(Fail over)한 시스템, 탄력성을 확보해야한다.

예를 들어, 결제 서비스에서 응답이 느려지더라도 이 장애가 주문 서비스나 API 게이트웨이까지 전파되어 시스템 전체가 마비되는 장애 전파(Cascading Failure)를 막아야한다.

3. 유지보수성 (Maintainability) & 관찰 가능성 (Observability)

시스템이 거대해질수록 코드 변경의 영향 범위를 파악하기 어려워진다. 모놀리스 아키텍쳐에서는 간단한 회원 등급 로직 변경이 아무 상관 없어 보이는 배송비 계산 로직에 버그를 유발할 수 있다. 따라서 현대의 아키텍쳐에서는 유지보수성, 관찰가능성을 확보해야한다.

  1. 유지 보수성: DDD(도메인 주도 설계)를 통해 각 서비스의 책임과 경계를 명확히 분리함으로써 개발자들은 코드 변경을 자유롭게하고 요구사항변경에 민첩하게 대응할 수 있게 한다.

  2. 관찰 가능성: MSA는 수많은 서비스가 상호작용하므로, 장애 발생 시 원인을 추적하기가 매우 어렵다. 주문 실패의 원인이 주문 서비스인지, 결제 서비스인지, 아니면 kafka 메시지 유실인지 어떻게 알 수 있을까? 이를 위해 우리는 분산 로깅, 메트릭, 분산 추적이라는 관찰 가능성의 세 축을 구축하여 복잡한 MSA 시스템 내부를 쉽게 볼 수 있게 만들어준다.

Spring Cloud

따라서 MSA를 잘 설계한다면 효율적이고, 탄력적이며, 유지보수가 용이해지게된다. 그렇다면 Spring 에서는 MSA를 어떻게 지원하고 있을까? 먼저 MSA로의 전환을 할 때 다음과 같은 문제에 직면하게 된다.

  1. 수십 개의 서비스가 서로 다른 IP와 포트에서 실행되는데 각 서비스를 잘 찾아가지 못하는 문제 (서비스 디스커버리)
  2. 사용자의 요청이 회원 서비스를 거쳐 주문 서비스로 전달될 때 인증 정보의 전파 방법(인증/인가)
  3. 외부 트래픽이 진입점에서 각 서비스로 요청을 어떻게 분배하는지(API 게이트 웨이)
  4. 상품 서비스에서의 장애가 다른 서비스의 장애로의 전파되는 것을 막는 문제(서킷 브레이커)
  5. 수백 개의 서비스에 흩어져있는 설정 파일을 어떻게 중앙에서 관리하고 변경사항을 일괄적으로 반영해야하는 문제(중앙 설정 관리)

이 문제를 Spring 에서는 Spring cloud를 통해 검증된 솔루션 세트를 제공하게 된다.

마치며

MSA에 대한 개념와 의의, 장,단점을 확인했으니 개발한 단계이다. 실제 트래픽은 아니지만 실제 트래픽 인 것처럼 요구사항을 머리속에서 정의하고 해결해나아가는 단계를 가져야겠다.