본문 바로가기

개발 스터디/MSA 공부

마이크로서비스 아키텍처(MSA) - #2 마이크로 서비스를 어떻게 분해할 것인가?

마이크로서비스 아키텍처의 핵심은 Y축 분해 즉 기능 분해이다. 그러면 대규모의 단일 애플리케이션을 어떻게 여러 서비스로 구성할 수 있을까? 그리고 마이크로 서비스 아키텍처는 소프트웨어 아키텍처랑 어떤 연관이 있을까? 

 

소프트웨어 아키텍처는 컴포넌트와 그들 간의 의존관계로 엮인 수준의 구조물이며 아키텍처에 따라 소프트웨어의 품질 속성 지표가 결정된다. 예전에는 확장성, 신뢰성, 보안 등의 아키텍처의 목표였지만, 이제는 신속하고 안전하게 소프트웨어를 배포하고 전달하는 것이 중요하다. 마이크로서비스 아키텍처는 그 중 관리성, 테스트성, 배포성이 높은 애플리케이션을 구축하는 데 장점을 가진 아키텍처 스타일이라고 할 수 있다.

 

마이크로 서비스 아키텍처는 애플리케이션을 느슨하게 결합된 여러 서비스로 구성하는 아키텍처 스타일이다.

이와 관련된 아키텍처 스타일은 크게 두 가지의 예를 들 수 있다.

 

- 계층화 아키텍처 스타일

애플리케이션을 다음 3계층으로 구성한 아키텍처이다.

  • 프레젠테이션 계층 : 사용자 인터페이스 또는 외부 API 가 구현된 계층
  • 비즈니스 로직 계층 : 비즈니스 로직이 구현된 계층.
  • 영속화 계층 : DB와의 상호 작용 로직이 구현된 계층.

단점 : 표현 계층이 하나 뿐임, 영속화 계층이 하나뿐임, 비즈니스 로직 계층을 영속화 계층에 의존하는 형태로 정의한다.

 

- 육각형 아키텍처 스타일

애플리케이션 표현 계층 대신에 비즈니스 로직을 호출하여 외부에서 들어온 요청을 처리하는 인바운드 어댑터들과, 영속화 계층 대신 비즈니스 로직에 의해 호출되고, 외부 애플리케이션을 호출하는 아웃바운드 어댑터를 둠.

 

비즈니스 로직에는 하나 이상의 포트가 있으며, 포트는 비즈니스 로직이 자신의 외부 세계와 상호작용하는 방법이 정의된 작업이다. 

비즈니스 로직에 있던 표현/ 데이터 접근 로직이 데이터와 분리되었기 때문에, 비즈니스 로직 표현/ 데이터 접근 로직 어디에도 의존하지 않는다는 장점이 있다. 

 

마이크로서비스에서 서비스의 의미

서비스는 어떤 기능이 구현되어 단독 배포가 가능한 소프트웨어 컴포넌트라고 할 수 있다. 서비스는 클라이언트, 혹은 다른 서비스에게 자신이 서비스 하는 기능에 접근할 수 있도록 커멘드, 쿼리, 이벤트를 API의 형태로 제공하며, 해당 API는 내부 구현 상세를 캡슐화하여 제공한다. 각각의 마이크로서비스는 자체 아키텍처를 갖고 있기 때문에 기술 스택을 독자적으로 구축할 수 있으며, 대부분 육각형 아키텍처 형태를 취한다. 

 

느슨한 결합

마이크로서비스 아키텍처를 구성할 때 중요한 것은 각 서비스간 느슨한 결합을 가져아한다는 것이다. 각 서비스는 구현코드를 감싼 API를 통해서만 상호작용하여, 클라이언트에 영향을 미치지 않고 서비스 구현 코드를 바꿀 수 있다. 이렇게 느슨하게 서비스가 결합 되면 전체 애플리케이션의 유지보수성 및 테스트 성을 높일 수 있다는 장점이 있다.

이렇게 느슨하게 결합되고, API를 통해서만 동작하기 때문에 다른 서비스는 해당 서비스의 DB와 직접적으로 통신하지 않게 되며, DB스키마 변경 시 다른 서비스의 개발자와 조율할 필요가 없다.

 

마이크로 서비스 아키텍처 정의

도메인 전문가가 문서로 정리한 요건들과 기존 애플리케이션을 출발점으로, 3단계 프로세스를 거쳐 정의한다.

 

1단계 : 시스템 작업 식별  - 사용자 스토리와 연관된 사용자 시나리오 등의 애플리케이션 요건을 정의한다. 고수준의 애플리케이션 도메인 모댈을 대략적으로 그려보고, 각 시스템 작업의 동작을 기술하는 데 필요한 단어를 정의한다. 도메인 모델이 정의 되었다면, 각 애플리케이션이 어떤 요청을 처리할 지 식별하여 명세를 정의 한다. 

 

2단계 : 서비스 분해 전략 결정

- 비즈니스 능력 패턴별 분해 : 비즈니스 능력은 비즈니스가 가치를 생산하기 위해 하는 일을 말함. 예를들어 쇼핑몰이라면 주문 관리, 재고 관리, 선적등의 능력을 의미한다. 그래서 비즈니스 능력은 보통 비즈니스 객체에 집중하며, 여러 개의 하위 능력으로 분해할 수 있으며 각 개발하고자 하는 소프트웨어의 도메인을 분석하여 비즈니스 능력을 도출하고, 분리하는 작업을 먼저 수행한다.

 

- 하위 도메인 패턴별 분해

DDD는 객체 지향 도메인 모델 중심의 소프트웨어 애플리케이션을 모델링하는 기법이다. DDD에서는 흔히 유비쿼터스 랭귀지라고 하는 도메인 전문가 및 개발자 등을 포함한 팀 전체에서 공용으로 사용하는 언어를 정의한다. DDD에는 마이크로 서비스 아키텍처에 적용할 수 있는 유용한 서브도메인과 바운디드 컨텍스트라는 개념이 있다.

 

기존에는 전체 비즈니스를 포괄하는 단일 통합 모델을 만들었으나, DDD에서는 범위가 분명한 도메인 모델을 여러개 정의하여 기존 방식의 문제접을 해결한다. 

DDD는 도메인을 구성하는 하위 도메인마다 도메인 모델을 따로 정의한다. 도메인 모델의 범위를 DDD용어로는 바운디드 컨텍스트라고 하며, 각 바운디드 컨텍스트는 코드 아티팩트를 포함하여, 마이크로서비스 아키텍처에 DDD를 적용한다면 각 서비스들이 바운디드 컨텍스트가 된다.

즉 정리하자면, DDD의 하위 도메인, 바운디드 컨텍스트 개념은 마이크로서비스 아키텍처의 마이크로서비스의 서비스의 개념과 잘 맞고, 각 도메인 모델을 개별 팀이 소유/개발 한다는 DDD의 사고방식과 유사하다. 

 

분해 원칙

- 단일 책임 원칙 : SRP와 관련되어 있으며, 하나의 서비스는 하나의 책임만을 가지고 응집되어야 한다.

- 공동 폐쇄 원칙 : 어떤 두 클래스가 동일한 사유로 맞물려 변경되면 동일한 패키지에 있어야 한다.

 

3단계 : 서비스 별 API 정의.

 

시스템 작업과, 서비스 후보를 목록화 했으면, 각 서비스별 API 즉 작업과 이벤트를 정의해야 한다. 우선 시스템 작업을 서비스로 배정하는 작업부터 시작해야한다.

 

먼저 어느 서비스가 요청의 진입점인지 설정해야 하며, 배정 이후에 서비스가 어떻게 협동해야할 지 정해야 한다.

 

 

서비스 분해의 장애물

- 네트워크 지연 : 서비스간 통신 비용이 증가하기 때문에 Delay가 발생한다. 따라서 갑비싼 IPC를 언어 수준의 메서드나 함수 호출로 대체하는 식으로 서비스 결합에 따른 지연시간을 줄일 수 있다.

- 동기 IPC로 인한 가용성 저하 : 보통 커뮤니케이션에 사용되는 REST API는 개발하기 쉽지만, 여러 맞물려있는 서비스들 중 하나가 불능이 된다면 가용성이 떨어진다는 문제가 존재한다. 따라서 이 것은 비동기 메시징으로 강한 결합을 제거할 수 있다.

- 데이터 일관성 유지 : 여러 서비스들은 독립적인 DB를 가지고 있기 때문에 전체에 걸쳐 트랜잭션을 보장하기가 어렵다. 이와 관련되어서 데이터의 일관성을 보장하기 위해 2PC 분산 트랜잭션이나 사가라는 방식을 도입해야 한다.