카테고리 없음

도메인 주도 설계로 시작하는 마이크로서비스 개발 - 2장 MSA의 이해

Hwisaek 2022. 11. 24. 14:40
반응형

아래는 "도메인 주도 설계로 시작하는 마이크로서비스 개발"의 2장을 정리한 내용이다.

 

2장 MSA의 이해

2. 1. 리액티브 선언: 현대 애플리케이션이 갖춰야 할 바람직한 속성들

 리액티브 선언은 다음과 같은 요소를 만족하는 시스템을 리액티브 시스템이라고 한다.

  • 응답성(Responsive): 사용자에게 신뢰성 있는 응답을 빠르고 적절하게 제공하는 능력
  • 탄력성(Resilient): 장애가 발성하거나 부분적으로 고장 나더라도 시스템 전체가 고장 나지 않고 빠르게 복구하는 능력
  • 유연성(Elastic): 시스템 사용량에 비례해서 자원을 늘이거나 줄이는 능력
  • 메시지 기반(Message Driven): 비동기 메시지 전달을 통해 위치 투명성, 느슨한 결합, 논블로킹 통신을 지향하는 것

 

 이러한 요소들을 만족하면 리액티브(reactive) 시스템이라는 이름에 맞게 상황에 맞춰 적응하는 시스템으로서 기능할 수 있다.

 

2. 2. 강 결합에서 느슨한 결합의 아키텍처로의 변화

 기존 모노리스 아키텍처 시스템들은 특정 제품에 의존하고 있어 해당 제품이 변경될 경우 많은 부분을 변경해야 할 정도로 강하게 결합되어 있는 경우가 많다. 이러한 경우에는 시스템의 변경이나 확장에 자유롭지 못하다는 단점이 있다.

 클라우드에서 사용 가능한 다양한 상용 오픈소스 제품들이 많으므로 위와 같은  단점을 극복하기 위해 적절한 오픈소스 또는 상용 제품을 선택하여 느슨하게 결합된 마이크로서비스 기반 아키텍처로 변화하는 것이 최근 분위기이다.

 

다음 링크에서 클라우드 네이티브 지형도를 확인할 수 있다.

 

https://landscape.cncf.io/

 

Cloud Native Landscape

The Cloud Native Landscape organizes all cloud native open source projects and proprietary products into categories, providing an overview of the current ecosystem

landscape.cncf.io

 

 

2. 3. 마이크로서비스의 외부 아키텍처와 내부 아키텍처

마이크로서비스 아키텍처는 밑에서부터 인프라, 플랫폼, 애플리케이션으로 구성되며 외부/내부 아키텍처는 다음과 같이 정의한다.

  • 외부 아키텍처: 인프라, 플랫폼, 애플리케이션 영역의 구성요소 및 관계
  • 내부 아키텍처: 마이크로서비스가 제공하는 API, 비즈니스 로직, 이벤트 발행, 데이터 저장 처리 등의 관계

 

2. 4. MSA 구성요소 및 MSA 패턴

 개발자는 MSA 시스템을 구현하기 위해 인프라, 플랫폼, 애플리케이션을 구축해야 한다.

 

2. 4. 1. 인프라 구성요소

 인프라는 물리적으로 직접 구축할지, 클라우드를 사용할지 선택을 할 수 있다. 클라우드로는 AWS, GCP, Azure 등 다양한 클라우드 사업자들이 있으며 여러 클라우드를 사용하여 서비스를 구축할 수도 있다. 

 

 

 인프라를 선택하고 나면 VM과 컨테이너 중 어떤 것을 사용할지 결정해야 한다. VM과 컨테이너는 다음과 같이 정리할 수 있다.

  • VM: 하이퍼바이저를 이용해 하나의 시스템에서 여러 운영체제를 사용
  • 컨테이너: 하이퍼바이저 없이 컨테이너 엔진을 이용

컨테이너는 게스트 OS를 사용하지 않으므로 VM보다 자원을 덜 소모하는 이점이 있다. 컨테이너 기술로는 현재 대부분 도커를 사용한다.

 

 컨테이너를 쓰기로 했다면 이제 컨테이너를 관리할 기술도 필요하다. 이러한 기술로는 도커 스웜, 쿠버네티스 등이 있는데 다양한 클라우드 사업자에서 쿠버네티스를 이용할 수 있도록 제공하고 있고 쿠버네티스를 대부분 많이 사용하고 있다.

 

 

2. 4. 2. 마이크로서비스 운영과 관리를 위한 플랫폼 패턴

 MSA를 위한 인프라 환경이 결정되었으면 이를 운영하고 관리하기 위한 개발 지원 환경이 필요하다. 개발 시에는 빌드, 테스트, 배포 등 다양한 작업이 필요한데 이러한 작업들을 자동화하여 높은 품질의 소프트웨어로 만드는 것이 중요하다. 

 

CI/CD

 이전에는 수동으로 빌드, 테스트, 배포를 하여  특정 기능을 개발하면 많은 시간이 소요됐다. 하나의 시스템이 여러 개 서비스로 분리된 MSA 환경에서는 이러한 작업이 더 빈번할 수밖에 없는데, 이를 모두 수동으로 하게 된다면 많은 시간이 소모되고 이는 개발 생산성 저하로 이어진다. 그래서 이를 자동화한 CI/CD 환경이 MSA에서는 매우 필요하다고 볼 수 있다.

  • CI(Continous Integration/지속적 통합): 빌드를 자동화하여 개발 생산성 및 소스코드 품질을 높이는 것
  • CD(Continous Deployment/지속적 배포, Continous Delivery/지속적 제공): 배포를 자동화하여 개발 생산성 및 소스코드 품질을 높이는 것

 

서비스 디스커버리 패턴

MSA 환경에서는 백엔드가 여러 마이크로서비스로 분산되어 있고, 여러 인스턴스로 복제되어 있다면 이를 호출하는 문제가 생긴다. 이를 위한 것이 서비스 디스커버리 패턴이다. 클라이언트는 하나의 라우터에게 요청을 하고, 라우터가 요청을 받아서 여러 마이크로서비스들의 인스턴스에 요청을 전달하도록 해야 한다.

 

서비스 레지스트리 패턴

라우팅을 위해서는 해당 인스턴스의 IP가 필요한데, 자유롭게 마이크로서비스가 확장되고 인스턴스가 복제되는 MSA 환경에서는 이를 관리하는 것이 쉽지 않다. 따라서 이를 매핑한 정보를 또 다른 공간에서 관리를 하는 것이 좋으며, 이를 서비스 레지스트리 패턴이라고 한다.

 

API 게이트웨이 패턴

 이러한 라우팅을 처리하는 라우터가 여러 개인 경우 관계가 복잡하게 되는데, 이를 하나의 진입점으로 통일시키면 관계도 단순해지고 인증/인가 등의 기능을 처리함에 있어서도 장점이 있다. 이러한 단일 진입점을 이용한 것을 API 게이트웨이 패턴이라고 한다.

 

BFF 패턴

 BFF(Backend For Frontend) 패턴은 웹, 안드로이드 앱, iOS 앱을 분리하여 이를 위한 진입점을 분리하는 것으로 해당 플랫폼을 위해 특화된 처리를 할 수 있도록 하는 패턴이다.

 

외부 구성 저장소 패턴

 DB 연결 정보, kafka 연결 정보 등의 설정 값이 애플리케이션에 포함되면 연결 정보 변경 필요시 애플리케이션 변경이 필요하다. 예를 들어 클라우드를 변경하게 되는 경우 애플리케이션 변경이 필요한데, 이러한 설정 값들을 별도로 분리하여 관리를 한다면 다른 환경에서 실행하더라도 코드 변경 없이 설정 값만 변경하여 바로 배포가 가능해진다.

 

인증/인가 패턴

 기존 모놀리식 아키텍처는 하나의 시스템으로 되어있어 서버에서 정보를 관리하고 이를 통해 인증/인가를 하는 방식을 많이 사용했다. 그러나 MSA에서는 자유롭게 확장될 수 있기 때문에 기존 방법으로는 관리하는 것이 어렵다. 이를 위해 여러 해결 방법이 있는데 이는 다음과 같다.

별도 세션 저장소
 Redis, Memcached 등의 별도 세션 저장소를 이용하여 여기에 세션 정보를 저장하고 관리하는 것이다. 

클라이언트 토큰 
 JWT를 이용해 클라이언트에서 인증 정보를 가지고, 서버에서 토큰을 검사하여 인증/인가를 하는 방식

클라이언트 토큰을 이용하게 되면 인증 정보를 클라이언트가 가지고 있으므로, 서버에서는 세션을 관리할 필요가 없다는 장점이 있다. 그러나 한번 발급한 토큰을 제거하지 못하는 등의 단점을 가지고 있다.

 

서킷 브레이커 패턴

MSA에서는 하나의 서비스에 장애가 발생하면 다른 서비스에 장애가 전파되지 않도록 해야 한다. 이를 위한 방법 중 하나가 서킷 브레이커 패턴이다. 이는 특정 서비스가 정상인지 지속적으로 감시(ex. 헬스체크)하여 장애 발생 시 클라이언트가 요청 시 해당 서비스의 응답을 대체하여 빠르게 응답하고, 장애 복구 시 정상화하는 것이다.

 

모니터링과 추적 패턴

여러 마이크로서비스를 실시간으로 모니터링하여 빠르게 장애를 감지하는 것은 중요한 일이다. 히스트릭스, 집킨 등을 이용하여 모니터링을 할 수 있다.

 

로그 중앙화

MSA에서는 로그가 여러 마이크로서비스에 분산되어 저장된다. 이때 장애가 발생하면 로그를 확인하는 것이 쉽지 않으며, 마이크로서비스가 확장, 축소되는 과정에서 로그가 사라질 수도 있다. 이를 위해 로그를 관리하는 도구를 이용하여 하나의 시스템에서 로그를 관리할 수 있다. 대표적으로 ELK 스택이 사용된다. ELK 스택은 Elasticsearch, Logstash, Kibana를 기반으로 구성된 것으로 로그를 중앙에서 집중 관리할 수 있으며, 알림 기능도 제공한다. 

 

2.4.3. 애플리케이션 패턴

 기능의 분리는 백엔드뿐만 아니라 프런트엔드도 필요하다. 모놀리식 프런트엔드는 사용자에게 느린 반응과 수정의 어려움이 존재한다. 이러한 프런트엔드를 기능 및 구성단위로 분리를 하고 이를 조합하여 화면을 보여준다면 사용자에게 더 나은 경험을 제공할 수 있다. 

 

UI 컴포지트 패턴

 화면을 기능별로 소스 레포지토리를 분리하고 이를 조합하여 하나의 화면을 보여줌으로써 독립적인 빌드와 배포가 가능해진다.

 

마이크로서비스 통신 패턴

 마이크로서비스로 구성된 시스템에서 클라이언트와 서버 간의 통신은 크게 다음과 같이 분류할 수 있다

동기 통신 방식
 클라이언트가 요청 시 마이크로서비스끼리의 통신도 동기 통신으로 하는 것이다. 모든 서비스가 동기 통신으로 연결되어있으면 결합이 강하게 되어있어 하나의 서비스에 장애가 발생하면 다른 서비스까지 장애가 전파될 수 있다.

비동기 통신 방식
 
비동기 통신 방식은 Kafka, RabbitMQ 등의 메시지 브로커를 이용한 메시지 기반의 비동기 통신을 하는 것이다. 

 

책에서는 비동기 통신의 예시로 커피숍을 들었다. 커피숍에서는 손님이 주문하면 바리스타가 주문을 받고 바로 커피를 만들고 주는 것이 아니다.
 손님이 주문을 하고 진동벨을 받고 대기하며, 주문 접수자가 주문을 받고 주문 목록을 바리스타에게 전달한다. 바리스타는 주문 목록을 순서대로 처리하여 음료를 제조하고 진동벨을 호출한다.

이처럼 주문 접수자와 바리스타 사이에 메시지 브로커가 존재하여 메시지로 주문 목록을 전달해주는 방식으로 비동기 처리가 된다는 것을 생각해보면 모든 사용자 요청이 동기 통신 방식으로 처리가 될 필요가 없다는 게 이해가 되었다.

 

저장소 분리 패턴

 마이크로서비스 별 DB를 따로 관리하며 다른 마이크로서비스의 DB에 직접 접근 불가하고 API로만 호출 가능해야 한다는 패턴이다. 이는 여러 서비스에 분산된 데이터 간의 정합성 및 일관성을 어떻게 보장할지 문제가 생긴다.

 

분산 트랜잭션 처리 패턴

 하나의 작업이 트랜잭션에 묶여서 처리되는 동기 통신 방식과는 달리 비동기 통신 방식에서는 트랜잭션이 분리되어 처리된다. 이를 위해서 서비스의 비즈니스 로직이 분산 트랜잭션에 맞게 데이터를 처리해야 하며, 각각 서비스 간의 트랜잭션이 제대로 처리됐는지는 메시지 큐를 이용해 비동기로 주고받는 것이 분산 트랜잭션 처리 패턴이다. 위의 커피숍 사례처럼 모든 작업이 동기 처리로 할 필요가 없다는 것을 보면 트랜잭션을 분산시키고 이벤트를 통해 처리 결과를 주고받으면서 마이크로서비스 간의 결합도를 낮출 수 있고 분리된 저장소 간의 일관성을 유지할 수 있다.

 

CQRS(Command Query Responsibility Segregation) 패턴(명령 조회 책임 분리)

 MSA에서는 확장된 인스턴스들이 하나의 저장소에 쓰기/읽기를 수행하다 보면 교착상태가 발생할 수 있다. 이를 해결하기 위한 방법이 쓰기용 모델/저장소와 읽기용 모델/저장소를 분리하여 관리하는 것이다. 대부분의 업무에서는 쓰기보단 조회가 대부분인데, 이를 위한 저장소를 분리하면 부하를 줄이고 교착상태도 해결이 가능하다는 것이 CQRS 패턴이다.

 

 

 

 

 

이상 책의 2장의 내용을 정리해보았다. MSA를 위한 시스템 구성 방법과 MSA에서 발생할 수 있는 여러 문제들을 해결하기 위한 패턴들이 정리된 내용이 있었다. 패턴 관련해서는 아직 좀 더 이해가 필요한 부분이 있으나(ex. CQRS 패턴) 남은 부분도 정리해가다 보면 이해가 될 것으로 예상한다. 

반응형