본문 바로가기
마이크로서비스

마이크로서비시 아키텍처 설계

by 이상한나라의개발자 2024. 10. 14.

소프트웨어 프로젝트에서 아키텍트의 역할은 해결해야 할 문제의 작동 모델(working model)을 제공하는 것이다. 아키텍트는 애플리케이션의 각 부분이 잘 조립될 수 있도록 개발자가 작성할 코드에 대한 뼈대를 제공한다. 마이크로서비스를 구축할 때 프로젝트의 아키텍트는 다음 세 가지 업무에 집중한다.

 

  • 비즈니스 문제 분해
  • 서비스 세분화 확정
  • 서비스 인터페이스 정의

 

1. 비즈니스 문제 분해

복잠함에 직면하면 대부분은 작업 중인 문제를 관리 가능한 덩어리로 쪼개려고 한다. 이렇게 하면 문제의 모든 세부 내용을 기억하지 않아도 되기 때문이다. 그들은 문제를 몇몇 필수적인 부분으로 나눈 후 이들 부분 사이에 존재하는 관계를 찾으려고 한다. 마이크로서비스 아키텍처에서도 이 과정은 매우 유사하다. 아키텍트는 비즈니스 문제를 각 활동 영역을 대표하는 덩어리(부분)로 분해하고 비즈니스 영역의 특정 부분과 연관된 비즈니스 규칙과 데이터 로직을 이 덩어리 안에 은닉하다. 예를 들어, 아키텍트는 코드로 수행될 비즈니스 흐름을 보고 고객과 제품 정보 모두 필요하다고 인식할 수 있다. 비즈니스 영역을 분해하는 것은 이분법적 과학이기보다 예술 행위에 가깝다. 비즈니스 문제를 식별하고 마이크로서비스 후보로 분해하는 데 다음 지침을 사용할 수 있다.

 

  • 비즈니스 문제를 기술하는 데 사용된 명사에 주목하라 : 문제를 기술하는 데 동일한 명사가 반복해서 사용된다면 핵심 비즈니스 영역과 마이크로서비스의 기회를 나타내는 좋은 징후다. 앨범, 곡, 권리사 등이다.
  • 동사에 주목하라 : 동사는 행동을 강조하고 종종 문제 영역의 윤곽을 자연스럽게 드러낸다. "트랜잭션 X는 어떤 A와 B에서 데이터를 가져와야 합니다." 라고 한다면 일반적으로 여러 서비스가 동작 중임을 암시한다. 예를 들어, "데스크톱 서비스 부서의 마이크는 새로운 PC를 셋업할 때 소프트웨어 X에 대한 가용 라이선스 수를 조회하고 라이선스 여분이 있다면 X를 설치한다. 그다음 장부에 사용된 라이선스 수를 업데이트한다." 여기에서 핵심 동사는 조회하다업데이트하다이다.
  • 데이터 응집성을 찾아라 : 비즈니스 문제를 개별 부분으로 나눌 때 서로 연관성이 높은 데이터 부분을 찾아야 한다. 통신 중 갑자기 지금까지 논의한 것과 전혀 다른 데이터를 읽고 업데이트 한다면 또 다른 서비스 후보가 나타났다고 볼 수 있다. 마이크로서비스는 완전히 자기 데이터를 가져야 하기 때문이다.

 

2. 서비스 세분화 확정

 

마이크로서비스를 구축할 때 세분화 질문은 필수적이다. 그래서 올바른 세분화 수준에 대한 정답을 구하려고 다음 개념들을 설명한다.

 

  • 마이크로서비스는 광범위하게 시작하고 더 작은 서비스로 리팩터링하는 것이 좋다 : 마이크로서비스 여정을 시작할 때는 모든 것을 마이크로서비스로 만들어 버리기 쉽다. 문제 영역을 작은 서비스로 분해하면 마이크로서비스가 단지 작은 데이터 서비스로 전락할 수 있기 때문에 조기에 복잡성을 많이 겪는다.
  • 서비스 간 교류하는 방식에 중점을 둔다 : 도메인 영역에 대한 큰 단위의 인터페이스를 만드는 데 도움이 된다. 큰 것을 작게 리팩터링하는 것이 더 쉽다.
  • 문제 도메인에 이해가 깊어지면서 서비스 책임도 계속 변한다 : 새로운 애플리케이션 기능이 요구될 때 대개 마이크로서비스가 그 책임을 맡는다. 마이크로서비스는 단일 서비스로 시작하여 여러 서비스로 분화되며 성장하는데, 원래 서비스는 새로운 서비스들을 오케스트레이션하고 애플리케이션의 다른 부분 기능을 캡슐화하는 역할을 한다.

나쁜 마이크로서비스의 징후는 어떤 것일까? 마이크로서비스가 적절한 크기인지 어떻게 확인할 수 있을까? 너무 큰 마이크로서비스는 다음 징후가 있다.

 

  • 책임이 너무 많은 서비스 : 해당 서비스에서 비즈니스 로직의 일반적 흐름이 복잡하고 지나치게 다양한 종류의 비즈니스 규칙을 시행하는 것처럼 보인다.
  • 다수 테이블에 걸쳐 데이터를 관리하는 서비스 : 마이크로서비스는 자기가 관리하는 데이터에 대한 기록이다. 여러 테이블에 데이터를 유지하거나 서비스의 데이터베이스 외부에 있는 테이블에 접근한다면 서비스가 너무 크다는 징조다. 마이크로서비스가 3~5개 정도의 테이블을 소유해야 한다는 지침을 사용하고 싶다. 이보다 더 많다면 서비스가 너무 많은 책임을 담당할 가능성이 높다.
  • 테스트가 너무 많은 서비스 : 서비스는 시간이 지남에 따라 규모와 책임이 커질 수 있다. 서비스가 적은 수의 테스트 케이스로 시작해서 수백개의 유닛 테스트와 통합 테스트로 끝나는 서비스가 있다면 리팩터링이 필요할 수 있다.

너무 작은 마이크로서비스는 다음 징후가 있다.

  • 문제 도메인의 한 부분에 속한 마이크로서비스가 토끼처럼 번식한다 : 모든 것이 마이크로서비스가 되면 서비스에서 비즈니스 로직을 구성하는 것이 복잡하고 어려워진다. 작업을 완료하는 데 필요한 서비스 수가 엄청나게 증가하기 때문이다. 흔한 징후는 애플리케이션에 수집개의 마이크로서비스가 존재하고 각 서비스가 하나의 데이터베이스 테이블과 통신할 때 나타난다.
  • 마이크로서비스가 지나치게 상호 의존적이다 : 문제 영역의 한 부분에 속한 마이크로서비스가 하나의 사용자 요청을 완료하려고 계속 서로 호출하고 있다는 것이 발견된다.
  • 마이크로서비스가 단순한 CRUD(Create, Read, Update, Delete) 서비스 집합이 된다 : 마이크로서비스는 비즈니스 로직의 표현이 데이터 소스의 추상화 계층이 아니다. 마이크로서비스가 CRUD 관련 로직만 수행한다면 너무 세분화된 것일 수 있다.

 

3. 서비스 인터페이스 설계

아키텍처에 대한 마지막 조언은 애플리케이션 내 마이크로서비스들의 상호 통신 방식의 정의에 관한 것이다. 마이크로서비스로 비즈니스 로직을 구축할 때 서비스의 인터페이스는 직관적이어야하고 개발자는 애플리케이션의 서비스 중 한두 개를 완전히 이해함으로써 모든 서비스가 어떻게 동작하는지  규칙을 습득해야 한다. 일반적으로 서비스 인터페이스 설계에 대한 다음 지침을 사용할 수 있다.

  • REST 철학을 수용하라 : 이것은 리처드슨의 성숙도 모델과 함께 모범 사례 중 하나다. 서비스에 대한 REST 접근 방식은 HTTP 동사(GET, PUT, POST, DELETE)를 사용하면서 서비스 호출 프로토콜로 HTTP를 수용하는 것이 핵심이다. HTTP 동사 기반으로 기본 행동 양식을 모델링하라.
  • URI를 사용하여 의도를 전달하라 : 서비스 엔드포인트로 사용되는 URI는 문제 영역에 존재하는 다양한 자원을 기술하고 자원 관계에 대한 기본 메커니즘을 적용한다.
  • 요청(request)과 응답(response)에 JSON을 사용하라 : JSON은 총 경량 데이터 직렬화 프로토콜이며 XML보다 휠씬 사용하기 쉽다
  • HTTP 상태 코드로 결과를 전달하라 : HTTP 프로토콜에 서비스 호출의 성공과 실패를 명시하는 풍부한 응답 코드가 있다. 상태 코드를 익히고 모든 서비스에 일관되게 사용하는 것이 매우 중요하다.

모든 기본 지침은 서비스 인터페이스를 쉽게 이해하고 소비할 수 있게 만드는 것이 목표이다.

 

마이크로서비스를 사용하지 말아야 할 때

마이크로서비스를 사용하지 말아야 할 때를 알아보자 

  • 분산 시스템 구축의 복잡성
  • 가상 서버나 컨테이너 스프롤
  • 애플리케이션 타입
  • 데이터 드랜잭션과 일관성

 

1. 분산 시스템 구축의 복잡성

마이크로서비스는 분산되고 세분화되어 있어 모놀리식 애플리케이션에서 없던 복잡성이 발생한다. 또한 마이크로서비스 아키텍처에서는 높은 운영 성숙도도 필요하다. 따라서 조직에서 고도로 분산된 애플리케이션을 성공시키는 데 필요한 자동화의 운영 작업(모니터링, 확장 등)에 기꺼이 투자하지 않는 한 마이크로서비스 사용을 고려하지 않는 편이 좋다.

 

2. 서버 또는 컨테이너 스프롤

마이크로서비스의 가장 일반적인 배포 모델은 컨테이너당 하나의 마이크로서비스 인스턴스를 배포하는 것이다. 대규모 마이크로서비스 기반 애플리케이션에서 운영 환경에서만 구축 및 관리해야 하는 서버나 컨테이너(보통 가상의 컨테이너)는 50~100개 정도일 수 있다. 그리고 클라우드에서 이들 서비스를 실행하는 데 드는 비용이 저렴하더라도 서버를 관리하고 모니터링하는 운영 작업은 엄청나게 복잡할 수 있다.

 

3. 애플리케이션 타입

마이크로서비스 재사용성을 추구하며 고도의 회복성과 확장성이 필요한 대규모 애플리케이션을 구축하는데 매우 유용하다. 이 점이 많은 클라우드 기반 회사에서 마이크로서비스를 채택하는 이유 중 하나다. 하지만 부서 수준의 소규모 애플리케이션이나 작은 사용자 기반의 애플리케이션을 만들 때 마이크로서비스와 같은 분산 모델로 구축한다면 연관된 복잡성 때문에 그 가치보다 더 많은 비용이 발생할 수 있다.

 

4. 데이터 트랜잭션과 일관성

마이크로서비스를 검토하기 시작할 때 여러분의 서비스와 서비스 소비자의 데이터 사용 패턴을 충분히 생각해야 한다. 마이크로서비스는 적은 수의 테이블을 추상화하며, 데이터 저장소에 단순한 (복잡하지 않은) 쿼리 생성, 추가, 실행 등 "운영성" 작업을 수행하는데 적합하다. 애플리케이션이 여러 데이터 소스에 걸쳐 복잡한 데이터를 집계하고 변환해야 한다면 마이크로서비스의 분산된 특성으로 이 작업은 어려워진다. 마이크로서비스는 어쩔 수 없이 과도한 책임을 떠않고 성능 문제에도 취약하게 된다.