Enjoy My Posts

msa 개요

Posted on By Geunwon Lim

이 포스트는 크리스 리처드슨 저의 마이크로서비스 패턴 1장과 이 블로그 글을 보고 작성했습니다.

MSA란

마이크로서비스 아키텍처 스타일은 단일 프로그램을 작은 서비스의 모음으로 개발하는 접근 방식이다. 각 작은 서비스들은 자체적으로 실행 가능하고, 경량 메커니즘(종종 HTTP 리소스 API)으로 서로 통신한다. 이러한 서비스들은 비즈니스 역량을 기반으로 구축되고 독립적으로 배포될 수 있다. 서로 다른 프로그래밍 언어로 작성되고 다른 데이터 저장 기술을 사용할 수 있기 때문에 서비스들의 중앙 집중식 관리는 거의 필요하지 않다. - 마틴 파울러

마이크로서비스 아키텍처를 경계 컨텍스트가 있는, 느슨하게 결합된 엘리먼트로 구성된 서비스 지향 아키텍처라고 정의할 수 있다. - 애드리안 콕크로프트

MSA가 필요한 이유

MSA는 어플리케이션을 단일 프로그램으로 개발하는 모놀리식 아키텍처가 갖는 단점 때문에 필요하다. 모놀리식 아키텍처의 단점을 살펴보기 전, 장점을 살펴보자.

  1. 개발이 간단하다: 여러 개발 툴은 모놀리식 어필르케이션 구축에 초점이 맞춰져 있다.
  2. 애플리케이션을 쉽게 변경할 수 있다: 코드, DB 스키마를 변경해 빌드/배포하기 용이하다.
  3. 테스트하기 쉽다: 앱을 띄우고, api 호출하고, 셀레늄 등으로 ui를 시험하는 종단 간 테스트를 하면 된다.
  4. 배포하기 쉽다: 톰캣 설치 경로에 war 파일을 복사하면 그만이다.
  5. 확장하기 쉽다: 부하 분산기 뒷면에 애플리케이션 인스턴스를 여러 개 실행하면 된다.

모놀리식 아키텍처가 본질적으로 나쁜 것은 아니다. 개발 초기에는 위와 같은 장점을 갖는다. 처음 아키텍트가 모놀리식 아키텍처를 선택할 당시에는 올바른 선택이었을 것이다. 하지만 시간이 지날수록 엉성한 테이프를 덕지덕지 붙여놓은 건물처럼 엉망이 될 가능성이 크다. 시간이 지날수록 개발, 테스트, 배포, 확장하기 어려워진다. 코드가 복잡해지기 때문에 모듈 구조를 문제 없이 유지하는 것이 어렵다. 응용 프로그램의 작은 부분에 대한 변경에도 전체 프로그램을 다시 빌드하여 배포해야 하기 때문에 배포 시간이 많이 걸린다. 어플리케이션의 언어, 프레임워크가 불가능한 것도 문제다.

마이크로서비스 아키텍처를 사용하면 독립적인 기능을 수행하는 작은 단위의 서비스로 분리하기 때문에 독립적으로 배치 가능하고 확장 가능할 뿐 아니라 서로 다른 프로그래밍 언어로 개발할 수 있다.

모놀리식 아키텍처의 단점

모놀리식 아키텍처는 근본적으로 한계가 있다. 개발 팀이 스프린트를 할 때마다 추가 구현할 스토리가 늘어났고 그만큼 코드베이스와 관리 오버헤드가 증가한다. 어플리케이션이 커짐에 따라 개발 인원도 충원되고, 많은 개발자가 협업하게 된다.

1. 너무 복잡해서 개발자가 주눅 들다

커다란 어플리케이션은 한 개발자가 완전히 이해할 수 없을 정도로 내용이 방대하다. 버그를 고치고 새 기능을 정확하게 구현하기가 갈수록 힘들고 시간도 오래걸린다. 단일 소스코드 저장소(코드베이스)는 소통/조정에 오버헤드를 유발한다. 또한 코드 커밋부터 프로덕션까지 과정이 길고 험난하며, 수동으로 테스트하게된다. 변경할 때마다 코드가 더 복잡하고 난해해지는 것도 문제다. JAR파일 수천 개 간의 디펜던시를 분석하는 툴도 이러한 스파게티 코드를 이해하고 개선하는 데 도움이 될 수 있지만, 아키텍처 측면에서 개선하는 것이 나을 수도 있다.

2. 개발이 더디다

어플리케이션이 너무 커져서 IDE 실행 속도도 느려지고, 빌드 시간도 오래 걸린다. 한 번 시동하는 것도 적잖은 시간이 필요하다. 코드를 고치고 빌드/실행 후 테스트하기까지 너무 많은 시간이 낭비된다.

3. 커밋부터 배포에 이르는 길고 험난한 여정

여러 개발자가 같은 코드베이스에 커밋하다보면 종종 릴리스할 수 없을 때도 있다. 브랜치로 문제를 해결할 수 있을 것처럼 보이지만, 고통스러운 소스 병합 단계를 극복해야 한다. 그래서 한 팀이 스프린트를 마치면 길고 긴 테스트 및 코드 안정화 기간이 필요하다. 테스트 시간이 너무 긴 것도 변경분을 프로덕션에 반영하는 데 시간이 많이 걸리는 요인이다. 변경 영향도가 제대로 파악이 안돼 CI서버에서 전체 테스트를 한 번씩 돌려보아야 한다.

4. 확장하기 어렵다

모놀리식 어플리케이션은 모듈마다 리소스 요건이 맞지 않아 확장하기 어렵다. 예를 들어 음식점 데이터와 이미지 데이터는 다른 서버에 두는 것이 바람직하다. 같은 어플리케이션이더라도 리소스 요건이 상이한 모듈이 존재하므로 서버 구성 시 리소스 배분을 신경써야 한다.

5. 확실하게 전달하기 어렵다

신뢰성이 부족하다. 덩치가 커서 철저하게 테스트하기 어렵고, 그로 인해 프로덕션에 버그가 발생할 수 있다. 전체 모듈이 같은 프로세스로 실행되기 때문에 결함 격리 되지 않고, 어떤 모듈에 버그 하나만 있어도 메모리 누수가 발생해 전체 애플리케이션 인스턴스가 내려가야 할 수 있다.

6. 갈수록 한물간 기술 스택에 발목이 붙잡힌다.

최신 기술을 사용하고자 전체 모놀리식 애플리케이션을 재작성 하는 것은 비용도 크고 리스크가 크다. 어쩔 수 없이 기존 기술을 쓰게된다.

좋은 개발자들이 노력하면 애플리케이션 모듈성을 유지하고 종합적인 자동화 테스트를 작성해 모놀리식 아키텍처가 단점을 겪는 시간을 늦출 수 있다. 하지만 근본적으로 여러 사람이 하나의 어플리케이션에 달라붙어 작업할 때 생기는 문제들은 불가피하고 기술 스택이 뒤쳐지는 것도 어쩔 수 없다.

MSA 특징

1. 서비스를 통한 컴포넌트화 - 모듈성

서비스는 비즈니스 로직 뿐 아니라 데이터베이스까지 독립적으로 개발하고 컴포넌트 간 상호 의존성이 없다. 너무 큰 어플리케이션은 한 사람이 이해하기 어렵기 때문에 모듈로의 분해가 필요하다. 마이크로서비스 아키텍처는 서비스를 모듈성의 단위로 사용한다. 각 서비스는 다른 서비스가 함부로 규칙을 어기고 침투하지 못하게 API라는 경계선을 갖고 있다. 또 서비스를 독립적으로 배포/확장할 수 있다.

2. 비즈니스 수행에 따른 구성

큰 응용프로그램을 분할할 경우 기술적 계층을 기반으로 UI팀, 비즈니스 로직팀, 데이터베이스팀으로 나눈다. 이러면 단순한 변경이 필요한 경우라도 많은 팀 간 협업이 필요할 수 있다. 마이크로 서비스는 비즈니스 로직에 따라 팀을 나눠, 각 팀에서 UI부터 데이버테이스까지 전부 관리한다.

3. DevOps

대부분의 응용 프로그램은 개발이 완료되면 소프트웨어 운영조직에 의해 관리되는데, 마이크로서비스 아키텍처의 각 팀은 제품의 전체 라이프사이클을 책임진다.

4. 분산된 데이터 관리

중앙 집중화된 하나의 데이터베이스를 사용하는 것이 아니라 서비스 별로 별도의 데이터베이스를 사용한다. 따라서 각 서비스에서 필요로 하는 데이터들의 중복 문제가 발생하고, 이런 중복을 동기화해야 한다. 각 서비스는 자체 DB를 가지고 있기 때문에 다른 서비스 개발자와 일일이 협의하지 않아도 개발자는 담당 서비스 스키마를 변경할 수 있다. 따라서 런타임에 다른 서비스가 DB락을 획득해 내 서비스를 블로킹하는 일 따위는 일어나지 않는다.

MSA 장점

1. 확장성

확장 큐브

확장 큐브는 애플리케이션을 확장하는 세 가지 방법을 정의한다. X축 확장은 동일한 다중 인스턴스에 들어온 요청을 부하 분산한다. Z축 확장은 요청의 속성에 따라 요청을 라우팅한다. Y축 확장은 애플리케이션을 기능에 따라 서비스로 분해한다. 즉, 어플리케이션을 X, Y, Z 세 방향으로 확장시킬 수 있다.

  1. X축 확장: 다중 인스턴스에 고루 요청 분산 - 일반적인 모놀리식 애플리케이션의 확장 수단이다.

  2. Z축 확장: 요청 속성별 라우팅 - 인스턴스별로 주어진 데이터 하위집합만 처리하도록 설정한다. 예를 들어, userId에 따라 라우터는 인스턴스에 요청을 라우팅한다. Z축 확장은 증가하는 트랜잭션 및 데이터 볼륨을 처리하기 좋다.

  3. Y축 확장: 기능에 따라 애플리케이션을 서비스로 분해 - X,Z축 확장은 애플리케이션 능력과 가용성은 개선하지만, 애플리케이션이 점점 복잡해지는 문제는 해결하기 어렵다. Y축 확장은 기능을 분해해 복잡해지는 문제를 개선한다. 여기서 중요한 건 크기가 아니라 각 서비스가 집중된/응집된 책임을 맡는다는 것이다.

서비스마다 X축, Z축 확장할 수 있고 상이한 리소스 요건에 맞춰 하드웨어에 배포할 수 있다. 리소스 요건이 전혀 다른(CPU 집약적 vs 메모리 집약적) 컴포넌트를 함께 배포할 수밖에 없었던 모놀리식 아키텍처와는 차이가 있다.

2. 각 서비스는 다른 프로그래밍 언어, 다른 도구를 사용하여 개발 가능

3. 개발팀이 일정관리에 있어서 자유도가 높음

4. 각 서비스는 팀별로 독립적으로, 지속적으로 개발/배포 가능

크고 복잡한 애플리케이션을 지속적으로 전달/배포할 수 있다. 테스트성, 배포성, 자율성/느슨한 결합으로 지속적 전달/배포를 실현한다.

5. 각 서비스는 심플하고 각 비즈니스 요구사항에 특화됨

서비스는 비교적 크기가 작아 개발자가 코드를 이해하기 쉽다. 서비스마다 자체 소스코드 저장소, 자체 자동화 개발 파이프라인을 가지고 있다.

6. 결함 관리가 잘 됨

한 서비스에서 메모리 누수가 발생해도 다른 서비스는 정상 가동된다.

7. 새로운 기술을 실험하고 도입하기 쉽다.

MSA 단점

1. 분산 시스템의 복잡성과 비동기성 - 개발, 테스트, 배포의 어려움

서비스 간 통신에 필수적인 IPC는 단순 메서드 호출보다 복잡하고, 사용 불능 또는 지연 시간이 긴 원격 서비스, 부분 실패한 서비스를 처리할 수 있게 설계해야 한다. 서비스마다 DB가 따로 있기 때문에 다중 DB에 접속하여 조회하고 트랜잭션을 구현하는 일이 어렵다. 단순 쿼리로는 여러 서비스에 있는 데이터를 조회하기 어렵다. IDE도 msa에 최적화되지 않았고, 여러 서비스가 연관된 테스트를 자동화하는 것도 어렵다. 운영 복잡도 역시 커진다.

2. 딱 맞는 서비스를 찾기 어려움

시스템을 분해하는 공식이 없다. 잘못 분해하면 모놀리식/마이크로서비스의 단점만 있는 분산 모놀리스가 된다. 반드시 함께 배포해야하는 결합도가 높은 서비스들로 이루어진 시스템을 만들게 된다.

3. 여러 서비스에 걸친 기능을 배포할 때 잘 조정해야 함

여러 서비스에 걸친 기능을 배포할 때는 여러 개발팀 간 세심한 조율이 필요하다. 여러 컴포넌트를 쉽게 원자적으로 업데이트할 수 있는 모놀리식 아키텍처와는 차이가 있다.

4. 도입 시점을 결정하기 어려움

초기 개발에는 msa가 별로 쓸모가 없다. 오히려 개발 속도가 더디고 신속하게 이터레이션 하기도 어렵다. 어플리케이션이 어느정도 커질 때, 즉 복잡성이 중요해질 때 기능 분해하는 것이 바람직하다.

5. 데이터의 중복

6. 서비스 간 통신 비용 증가

7. 코드의 중복

MSA를 적용할 시 고려해야 할 사항

  1. 서비스 간 통신을 어떻게 할 지
  2. 데이터 일관성을 어떻게 유지해야 할 지
  3. 데이터 쿼리를 어떻게 할 지
  4. 배포를 어떻게 할 지
  5. 문제의 원인을 어떻게 관측하고 진단할 지
  6. 서비스 간 테스트를 어떻게 할 지
  7. 횡단 관심사(관측성, 디스커버리 등)를 어떻게 처리할 지
  8. 보안을 어떻게 할 지

MSA vs SOA

  SOA 마이크로서비스
서비스 간 통신 SOAP, WS표준처럼 무거운 프로토콜 사용 REST, gRPC처럼 가벼운 프로토콜 사용
데이터 전역 데이터 모델/공유DB 서비스 개별 데이터 모델 및 DB
주요 사례 대규모 모놀리식 애플리케이션 소규모 서비스