본문 바로가기
MSA

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

by nozee 2021. 11. 8.
반응형
해당 포스트는 도메인 주도 설계로 시작하는 마이크로 서비스 개발 책을 개인적으로 요약한 내용입니다. 


2. MSA의 이해

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

사람들은 여러 기기에 포함된 애플리케이션이 요청에 즉각 응답하고 항상 가동되길 기대한다. 이 같은 현대 애플리케이션에 대한 기대를 잘 표현한 문서가 있는데, 바로 2014년 요나스 보네르 등이 선언한 리액티브 선언문이다.

리액티브 선언문에서는 응답성(Reponsive), 탄력성(Resilient), 유연성(Elastic), 메세지 기반(Message Driven)이라는 4가지 특성을 강조하고, 이러한 요건을 만족하는 시스템을 리액티브 시스템이라고 정의한다.

 

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

즉, 급변하는 상황에 적응할 수 있는 시스템을 요구하는 것이다.

 

 

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

예전에는 아키텍처의 구성요소들을 각 기업이나 특정 벤더의 제품에 전적으로 의존해서 구축하거나 수정이 필요한 부분만 별도로 직접 개발하는 경우가 많았다. 이처럼 특정 벤더에 의존한다는 점에서 기술의 락인이 되어 쉽게 변경하지 못하게 된다.

그러나 최근에는 오픈소스에 대한 신뢰도가 많이 올라가고 지원하는 범위가 높아지고 있어 오픈 소스를 많이 채택하여 사용하고 있다.

예전에는 특정 업체의 제품들을 사용하여 강 결합 위주였다면 요즘은 다양한 오픈소스를 활용해 유용하고 느슨하게 결합되는 마이크로서비스 기반 아키텍처로 진화하고 있다.

클라우드 네이티브 지형도

 

2.3 MSA 구성요소 및 MSA 패턴

인프라 구성요소 : 마이크로서비스를 지탱하는 하부구조 인프라를 구축하는 데 필요한 구성요소

플랫폼 패턴 : 인프라 위에서 마이크로서비스의 운영과 관리를 지원하는 플랫폼 차원의 패턴

애플리케이션 패턴 : 마이크로서비스 애플리케이션을 구성하는 데 필요한 패턴

 

2.3.1 인프라 구성요소

인프라를 AWS, 구글, 마이크로소프트, IBM, 등 세계적인 플랫폼 사업자들이 자동화된 IaaS(Infrastructrue as a Service), Paas(Platform as a Service를 통해 쉽고 편하게 이용할 수 있게 제공한다. 클라우드가 아닌 실제 장비를 통해 구축을 할 수도 있지만 장비는 필요에 따라 유연한 축소/확장 기대하기 힘든 구조기 때문에 추천을 하지는 않는다.

 

그다음은 가상화다. Vmware라던지 도커를 통해 가상화를 진행을 많이 하고 있다. Vmware를 사용할 경우에는 운영체제 패치, 라이브러리 설치 같은 오버헤드가 발생하기 때문에 추천하고 있지는 않다.

마이크로 서비스 같은 작은 서비스에는 패키지하고 배포할 수 있는 컨테이너 환경이 더 적합하다. 컨테이너 중에서도 도커가 가장 많이 사용되고 있어 실질적 표준으로 자리 잡고 있다.

 

도커의 장점

  • 이식성 : 어떠한 호스트 커널이나 플랫폼 버전에 상관없이 도커만 실행할 수 있으면 사용 가능하며 동일하게 동작한다.
  • 신속성 : 크기가 작고 가볍기 때문에 빠르게 배포 가능하며, 문제 발생 시 수정할 필요 없이 새로 기동 하면 된다.
  • 재사용성 : 동일한 환경을 재사용해서 쉽게 설정 가능하기 때문에 개발, 테스트, 스테이징, 프로덕트 환경을 동일한 환경으로 구축하기 쉽다.

컨테이너 기술을 선택했다면 컨테이너를 관리하기 위한 기술 또한 필요하다. 컨테이너가 많아 지면 그에 따라 컨테이너의 자동 배치 및 복제, 장애 복구, 확장 및 축소, 컨테이너 간 통신, 로드 밸런싱 등의 컨테이너 관리를 위한 기능이 필요해진다. 최근에는 쿠버네티스가 큰 인기를 끌고 있다.

 

쿠버네티스 장점

  • 자동화된 자원 배정 : 각 컨테이너가 필요로 하는 CPU와 메모리를 쿠버네티스에 요청하면 컨테이너를 노드에 맞춰 자동으로 배치한다.
  • 셀프 치유 : 컨테이너의 이상 유무를 점검해서 실패한 경우 자동으로 교체하고 재스케쥴링한다.
  • 수평 확장 : 일정 CPU 및 메모리 사용량을 초과하면 자동으로 확장한다.

 

서비스 유형별 대표적인 클라우드


IaaS
(Infrastructrue as a Service) : 가상 머신, 스토리지, 네트워크 같은 인프라를 필요한 만큼 적시에 제공하는 서비스로서 사용자는 이러한 인프라를이용해 개발 환경을 구성한 후 애플리케이션을 배포한다. 가상서버, 가상 네트워크, 가상 스토리지라 생각하면 이해가 쉽다.
예) AWS EC2(Elastic compute Cloud), GCP Compute Engine, Azure VM

CaaS(Container as a Service) : 컨테이너 기반 가상화를 사용해 컨테이너를 업로드, 구성, 실행, 확장, 중지할 수 있는 서비스다. 애플리케니션을 바로 구동할 수 있는 환경을 제공한다는 점에서 PaaS와 유사하지만 다른 환경에도 이식 가능한 컨테이너 기반 가상화를 제공한다는 점이 다른다.
예) 마이크로소프트 Azure Kubernetes Service(AKS), 아마존의 Elastic Kubernetes Service(EKS), Google Kubernetes Engine(GKE), AWS ECS

PaaS(Platform as a Service) : 복잡함 없이 애플리케이션을 곧바로 개발, 실행 관리할 수 있는 플랫폼 환경을 서비스 형태로 제공한다. IaaS 위에 실제로 애플리케이션이 실행될 수 있는 미들웨어나 런타임까지 탑재된 환경이라 생각하면 이해하기 쉽다.
예) Azure Web App, Google App Engine, Cloud Foundry, Heroku, AWS Elastic Beanstalk

 

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

인프라 환경을 결정했다면 그다음으로 선택한 인프라 환경 위에서 애플리케이션을 운영하고 관리하는 환경을 구성하는 방법을 생각해야 한다.

 

데브옵스 인프라 구성

자동화된 빌드나 배포 작업을 보통 CI/CD라고 하며, 여기서 CI는 지속적 통합(Continuous Integration)을 가리킨다.

자동으로 통합 및 테스트하고 그 결과를 리포트로 기록하는 활동을 CI라 하고, 실행 환경에 내보내는 활동을 CD라고 한다.

CD는 지속적 제공(Continuous Delivery) 및 지속적 배포(Continuous Deployment)를 의미하고 있다.

지속적 제공 : 빌드된 소스코드의 실행 파일을 실행 환경에 반영하기 전 단계까지 진행하는 방식이다.

지속적 배포 : 소스코드 저장소에서 빌드한 소스코드의 실행 파일을 실행 환경까지 자동으로 배포하는 방식을 말한다.

 

빌드/배포 파이프라인 설계

아래 그림이 전형적인 빌드/배포 파이프라인이다. 여기에 UI 테스트, 배포 승인 프로세스 등을 추가하여 재설계할 수도 있다.

최근에 인프라 구성을 마치 프로그래밍하는 것처럼 처리하고 소수의 인원으로 많은 컨테이너 배포 처리를 할 수 있게 됐는데, 이를 가리켜 Infrastucture As Code라고 한다.

 

마이크로서비스 생태계와 운영 관리 요소의 탄생

2001년에 애자일 선언을 한다. 그때부터 소프트웨어 업계가 장기적인 계획이나 단계적 프로세스 대신 빠른 실패와 피드백을 기반으로 하는 실용적인 실천법을 선호한다.

2006년 아마존에서 EC2사업을 선언하고 넷플릭스에서 마이크로서비스 기반의 시스템으로 전환하는 작업을 시작한다.

넷플릭스에서는 여러 문제를 겪으며 문제를 해결할 수 있는 서비스와 도구를 개발하게 된다. 그것들을 오픈소스로 공개를 하였고 넷플릭스 OSS(Open Source Software) 줄(Zuul), 히스트릭스, 유레카(Eureka) 등이 있다.

 

 

넷플릭스 OSS



Zuul : 동적 라우팅, 모니터링, 회복성, 보안 등을 제공하는 게이트웨이 서비스 넥플릭스 스트리밍 애플리케이션의 백엔드에 대한 모든 요청을 담당하는 관문

Eureka : 유레카 중간-계층(middle-tier) 서버들에 대한 로드밸런싱과 페일오버 하기 위한 REST 기반 서비스 AWS 클라우드 환경 중심

Hystrix : 히스트릭스 “서킷 브레이커” 라이브러리 격리 패턴 구현체 라이브러리 분산 시스템을 위한 Latency 및 Fault Tolerance 원격 시스템이나 서비스를 호출하는 구간을 격리해 관리하고 모니터링하는 라이브러리 슬로건: “Defend Your App”

Ribbon : 클라이언트 측 로드 밸런서 여러 서버를 라운드로빈 방식의 부하 분산 기능을 제공(여러 알고리즘 사용 가능) Spring Cloud Config와 결합하여, 서버 목록을 제공받아 사용할 수 있음

 

 

경험으로 획득한 지혜:마이크로 서비스 관리/운영 패턴

스프링 진영의 피보탈에서는 기존의 스프링 부트 프레임워크에서 잘 돌아갈 수 있도록 넷플릭스 OSS 모듈들을 스프링 프레임워크로 감싸서 스프링 클라우드라는 명칭으로 발표했다. 이를 통해 스프링 부트와 스프링 클라우드는 마이크로서비스를 개발하기 위한 가장 대중적인 기본 프레임워크로 자리매김했다.

 

다양한 서비스의 등록 및 탐색을 위한 서비스 레지스트리, 서비스 디스커버리 패턴

프론트엔드 클라이언트가 여러 개의 백엔드 마이크로서비스를 어떻게 호출해야 할까? 또한 스케일 아웃을 통해 인스턴스가 여러 개로 복제됐다면 어떻게 부화를 적절히 분산할 수 있을까?

이를 위한 패턴이 서비스 디스커버리(Service Discovery) 패턴이다. 클라이언트가 여러 개의 마이크로서비스를 호출하기 위해서는 최적 경로를 찾아주는 라이퉁 기능과 적절한 부하 분산을 위한 로드 밸런싱 기능이 제공돼야 한다. 넷플릭스의 OSS로 예를 들면 라우팅 기능은 줄(Zuul) , 로드밸런싱은 리본(Ribbon)이 담당한다.

백엔드 마이크로서비스 의 명칭과 유동적인 IP 정보를 매핑해서 보관할 저장소가 필요하다. 넷플릭스 유레카(Eureka)가 그 기능을 담당하고, 이러한 패턴을 서비스 레지스트리 패턴이라 한다.

서비스 단일 진입을 위한 API 게이트 패턴

여러 클라이언트가 여러 개의 서버 서비스를 각각 호출하게 된다면 매우 복잡한 호출 관계가 만들어질 것이다. 이 해결책은 API 게이트웨이로 해결할 수 있다. 클라이언트에 따라서 다른 API 조합을 제공할 수도 있고, 각 서비스에 접근할 때 필요한 인증/인가 기능을 한 번에 처리할 수도 있다.

 

API 게이트웨이 기능

  • 레지스트리 서비스와 연계한 동적 라우팅, 로드 밸런싱
  • 보안: 권한 서비스와 연계한 인증/인가
  • 로그 집계 서비스와 연계한 로깅. 예: API 소비자 정보, 요청 응답 데이터
  • 메트릭(Metrics) 예: 에러율, 평균/최고 지연시간, 호출 빈도 등
  • 트레이싱서비스와 연계한 서비스 추적. 예: 트래킹 ID 기록
  • 모니터링 서비스와 연계한 장애 결리(서킷 브레이커 패턴)

 

이러한 API게이트웨이 패턴은 스프링 클라우드의 스프링 API 게이트웨이 서비스라는 제품으로 구현할 수 있다. 마찬가지로 쿠버네티스의 경우 자체 기능인 쿠버네티스 서비스와 인그레스 리소스로 제공한다.

 

 

BFF 패턴

BFF 패턴은 API게이트웨이와 같은 진입점을 하나로 두지 않고 프론트엔드의 유형에 따라 각각 두는 패턴이다.

출처 : https://engineering-skcc.github.io/microservice outer achitecture/outer-arch-api-gw/

 

 

외부 구성 저장소 패턴

클라우드 인프라와 같이 유연한 인프라를 사용하는 상황에서 데이터베이스 연결 정보, 파일 스토리지 정보 같은 내용을 애플리케이션에 포함하면 변경 시 반드시 재배포해야 하는데, 이 경우 서비스를 중단해야 한다. 따라서 마이크로서비스가 사용하는 자원의 설정 정보를 쉽고 일관되게 변경 가능하도록 관리할 필요가 있다.

 

예를 들면 , 그림과 같이 스프링 클라우드 컨피그(Spring Cloud Config)를 이용하면 이러한 환경 정보를 코드에서 분리하고 컨피그 서비스를 통해 런타임 시 주입되게 할 수 있다. Git과 같은 별도 형상관리 리포지토리에 보관하고 특정 환경에 배포될 때 적절한 환경 정보를 형상관리 리포지토리에 가져와 해당 서비스를 주입한다.

 

인증/인가 패턴

각 서비스가 모두 인증/인가를 중복으로 구현한다면 비효율적이다. 따라서 마이크로서비스 인증/인가를 처리하기 위해서는 일반적으로 다음과 같은 패턴을 활용한다.

 

  • 중앙 집중식 세션관리
  • 마이크로서비스에서 는 각자 서비스에 세션을 저장하지 않고 공유 저장소에 세션을 저장하고 모든 서비스가 동일한 사용자 데이터를 얻게 한다. 이때 세션 저장소로 보통 레디스(Redis)나 멤캐시드(Memcached)를 사용한다.
  • 클라이언트 토큰
  • 세션은 중앙 서버에 저장되고 토큰은 사용자의 브라우저에 저장된다. 토큰은 사용자의 신원 정보를 가지고 서버로 요청을 보낼 때 전송되기 때문에 서버에서 인가처리를 할 수 있다. JWT(JSON Web Token)는 코튼 형식을 정의하고 암호화하여 다양한 언어에 라이브러리를 제공하는 공개 표준이다.
  • API 게이트웨이를 사용한 클라이언트 토큰
  • 사용자 인증 프로세스는 토큰 인증 프로세스와 유사하다. 차이점은 API 게이트웨이가 외부 요청의 입구로 추가되는 것이다. 이러한 서비스를 인증 서비스(auth service) 라 하는데, API게이트웨이와 연동해서 인증/인가 처리한다. 인증 서비스를 이용하면 각 리소스 서비스가 자체적으로 인증/인가를 처리하지 않고 업무 처리에 집중할 수 있다.

 

장애 및 실패 처리를 위한 서킷 브레이커 패턴

여러 서비스로 구성된 시스템에서는 한 서비스에 장애가 발생했을 때 다른 서비스가 영향을 받을 수 있다. 이때 장애가 발생한 서비스를 격리해서 유연하게 처리할 수 있는 방법이 필요한데, 이를 위한 방법이 서킷 브레이커 패턴이다.

특정 서비스에서 장애가 발생했을 때 다른 서비스에도 장애가 옮겨가게 된다. 장애가 옮겨가지 않게 하는 방법이 필요한데 전기회로 차단기와 비슷하다고 해서 서킷 브레이커 패턴이라고 한다.

 

모니터링과 추적 패턴

마이크로서비스의 장애는 어떻게 감지할 수 있을까? 서킷 브레이커 패턴을 가능하게 하려면 각 마이크로서비스의 장애를 실시간으로 감지해야 하고, 서비스 간의 호출이 어떤지 알아야 한다. 즉 모니터링하고 추적하는 패턴이 필요하다. 스프링 클라우드에서는 히스트릭스라는 라이브러리를 제공하고, 히스트릭스 라이브러리가 배포된 서비스를 모니터링할 수 있는 히스트릭스 대시보드를 제공함으로써 실시간으로 모니터링할 수 있다.

다음은 분산 트레이싱 서비스다. 모니터링과 함께 각 서비스 트랜잭션의 호출을 추적하면 마이크로서비스 운영에 매우 유용하다. 트위터에서 공개한 집킨(Zipkin)이라는 오픈소스 프로젝트의 대시보드로 분산된 서비스 간의 호출이나 지연 구간별 장애 포인트를 확인할 수 있다.

 

중앙화 된 로그 집계 패턴

마이크로서비스의 로그는 어떻게 관리해야 할까? 마이크로서비스가 사용량에 따라 탄력적으로 변화하면서 언제든지 인스턴스가 생성/삭제되는 과정에서 로컬 로그가 초기화될 수 있다.

중앙화 된 로그 집계 패턴이 필요하다. 대표적으로 많이 쓰는 기술이 ELK스택이다. ELK스택은 엘라스틱서치(Elasticsearch), 로그스태시(Logstash), 키바나(Kibana)라는 세 가지 오픈소스 프로젝트를 기반으로 데이터 분석 환경을 구성한 것이다.

 

  • Elasticsearch : 분산형 검색, 분석 엔진
    • 정형, 비정형, 위치 정보, 메트릭 등 원하는 방법으로 검색을 수행, 결합 가능
  • Logstash : 로그 집합기
    • 데이터 처리 파이프라인. 다양한 소스에서 동시에 데이터를 수집해 변환한 뒤 특정 보관소로 데이터를 보냄
  • Kibana : 시각화
    • 히스토그램, 막대그래프, 파이 차트 등 표현, 위치 데이터, 시계열 분석, 그래프 관계 탐색 등 지원

마이크로 서비스에서 보낸 로그가 중앙 레디스에 쌓이면 레디스에서 중앙 관리 저장소에 로그를 보내고, 이 로그 저장소에 엘라스틱서치 엔진이 로그를 인덱싱하고 해당 로그 정보가 키바나 데시보드를 통해 보인다. 중간에 레디스를 놓은 이유는 로그 스트림이 너무 몰리면 로그 저장소 서비스에도 문제가 생기기 때문에 중간 임시 저장소를 추가한 것이다.

 

 

 

MSA 기술 변화 흐름

앞에서 언급한 패턴들은 모두 모노리스 시스템이 여러 조각의 마이크로서비스로 나눠져서 발생하는 문제들을 해결한다. 추적, 모니터링, 로깅, 인증, 탐색, 유연성, 탄력성 등이 여기에 해당된다.

초기 MSA 생태계에서는 넷플릭스OSS나 스프링 클라우드를 이용해 각각의 서비스를 별도로 만들어서 해결하거나 유연성처럼 수평 확장이 필요한 요소는 AWS IaaS 서비스를 이용해서 해결했다.

하지만 이후 여러 문제의 해결책을 한꺼번에 제공하는 솔루션들이 등장했는데, 바로 쿠버네티스나 오픈시프트(OpenShift) 같은 제품이다. 컨테이너의 레플리카 기술로 탐색, 호출 문제와 함께 통합해서 지원하면서 쿠버네티스가 각광받고 있다.

그런데 최근 동향은 쿠버네티스에 덧붙여 이스티오 기술이 함께 사용되고 있다.

 

서비스 메시지 패턴

초창기 MSA 기술인 넷플릭스 OSS나 스프링 클라우드 기반의 서비스를 구축 및 운용할 때의 문제점은 API 게이트웨이, 서비스 레지스트리, 컨피그 서비스와 같이 운영 관리를 위한 여러 개의 기반 서비스를 별도로 각각 만들어야 한다는 번거로움과 업무 처리 마이크로서비스에 스프링 클라우드 서비스를 사용하기 위한 라이브러리를 비즈니스 로직과 함께 탑재해야 한다는 점이다.

또한 스프링 클라우드는 자바 기반이기 때문에 자바가 아닌 폴리그랏을 구현할 경우 스프링 클라우드 서비스를 아예 사용할 수 없다.

그래서 최근에는 MSA 문제 영역 해결을 위한 기능(서비스 탐색, 서킷 브레이크, 추적, 로드 밸런싱 등)을 비즈니스 로직과 분리해서 네트워크 인프라 계층에서 수행하게 하는 서비스 메시지 패턴이 선호되고 있다.

구글 이스티오는 애플리케이션 배포되는 컨테이너에 완전히 격리되어 별도의 컨테이너로 배포되는 사이드카(Sidecar) 패턴을 적용해서 서비스 디스커버리, 라우팅, 로드 밸런싱, 로깅, 모니터링, 보안, 트레이싱 등의 기능을 제공한다.

스프링 클라우드와 넷플릭스 OSS를 이용한 경우에는 스프링 클라우드로 각 서비스를 먼저 구축하고 마이크로서비스 애플리케이션 자체도 코드 내부에 스프링 클라우드 사용을 위한 클라이언트 코드가 탑재돼야 한다. 그렇지만 서비스 메시지를 적용하는 경우에는 마이크로 서비스마다 함께 배포되는 사이드카 프락이세 운영 관리를 위한 별도 기능이 담겨있기 때문에 마이크로서비스는 순수 비즈니스 로직에 집주할 수 있다.

컨트롤 플레인 기능에 의해 중앙세어 통제되며, 사이드카끼리 통신해서 관련 운영 관리 기능을 제공하는 모습을 보여준다. 이를 통해 마이크로 서비스의 비즈니스 로직과는 완벽하게 독립적으로 운영된다.

이스티오 주요 기능

  • 트래픽 관리(Traffic management): 동적 라우팅, 로드 밸런싱
  • 보안: 보안 통신 채널(TLS), 인증/인가/암호화
  • 관측성(Observability):메트릭, 분산 트레이싱, 로깅

스프링 클라우드 및 넷플릭스 OSS와의 차별점

  • 애플리케이션 코드의 변경이 거의 없다. 스프링 클라우드나 넷플릭스OSS 기반은 비즈니스 로직과 함께 코드로 표현돼야 하지만 이스티오는 완전히 사이드카로 격리되며 yaml 파일과 같은 설정 파일에 의해 정의된다.
  • 폴리그랏 애플리케이션도 지원한다. 스프링 클라우드나 넷플릭스 기반은 자바 언어만 지원하나 이스티오는 각 마이크로서비스를 다른 언어로 작성한 경우에도 지원 가능하다.
  • 이스티오는 쿠버네티스와 완벽하게 통합된 환경을 지원한다.

 

 

2.4.3 애플리케이션 패턴

프론트엔드의 패턴을 살펴보자. 프론트엔드도 백엔드와 마찬가지로 모노리스가 가지고 있었던 문제들이 생기게 된다. 기능 하나만 수정을 하게 되어도 전체 빌드를 해서 배포를 해야 한다.

 

UI컨포지트 패턴 또는 마이크로 프론트엔드

마이크로서비스팀은 별도의 독립된 소스 리포지토리에 백엔드 마이크로서비스와 마이크로 프론트를 관리하고, 이를 독

립적으로 빌드 및 배포할 수 있다.

 

마이크로서비스 통신 패턴

  • 동기 통신 방식 이러한 방식은 요청을 보낸 서비스에서 다른 서비스를 호출을 할 수 있게 되는데 도중에 문제가 생길 경우 장애 전달이 되어 업무에 문제가 생길 수 있다.
  • 동기 호출 방식은 클라이언트에서 서브 측에 존재하는 마이크로서비스 REST API를 호출할 때 사용되는 기본 통신 방법이며, 다양한 클라이언트 채널 연계나 라우팅 및 로드 밸런싱을 원활하게 하기 위한 방법으로 중간에 API게이트웨이를 둘 수 있다.
  • 비동기 통신 방식 이러한 메커니즘에서는 메시지를 보내는 생성자(producer)와 메시지를 가져다가 처리하는 소비자(consumer)가 서로 직접 접속하지 않고 메시지 브로커에 연겨로딘다. 메시지 브로커에 메시지를 전달하고 자신의 일을 처리하면 메시지 브로커가 전송을 보장하게 된다.
  • 메시지를 보낸 다음 응답을 기다리지 않고 다음 일을 처리한다. 물론 보낸 결과가 어떻게 됐는지 응답을 받지 않으므로 동기식처럼 완결성을 보장할 수는 없다. 따라서 이를 보장하기 위한 메커니즘이 필요한데, 보통 아파치 카프카, 래빗엠큐, 액티브엠큐 같은 메시지 브로커를 활용한다.

커피숍에서 손님이 주문을 하면 주문 접수자는 주문을 받는다. 그리고 바리스타에게 커피 제작을 의뢰한다. 이때 주문 접수자는 하나의 주문이 바리스타에 의해 완료될 때까지 마냥 주문을 받지 않고 기다리지는 않는다. 즉, 주문접수 → 커피제작 → 고객전달이라는 하나의 무결하고 완결된 단위로 다루지 않는다.

대신 주문이 들어오는 대로 꾸준히 주문 목록에 적고 동시에 커피 주문이 들어왔다는 이벤트를 바리스타에게 계속 전달한다. 그럼 바리스타도 마찬가지로 커피 주문 이벤트를 순차적으로 제작 목록에 기입하고 주문에 해당하는 커피를 만든다. 커피 제작이 완료되면 커피 제작 완료 이벤트를 보내고, 이것이 진동벨을 통해 손님에게 통보되는 것이다.

 

 

저장소 분리 패턴

기존 모놀로지 방식은 한 데이터베이스에 SQL로 호출을 하게 된다. 업무 규칙 및 흐름 처리를 수행하는 애플리케이션의 코드 라인 수보다 SQL코드의 라인 수가 몇 배 이상이다.

이러한 구조를 데이터 중심 애플리케이션이라 하는데, 이러한 경우 유지보수가 어려워지고 성능 문제가 발생했을 때 SQL구문 튜닝이나 저장소 중설에 의존할 수밖에 없다.

이를 보완 할 수 있는 마이크로서비스 패턴인 저장소 분리 패턴을 보면 각자의 비지니스를 처리하기 위한 데이터를 집접 소유를 하고 있다. 그렇기 때문에 자신이 소유한 데이터는 다른 서비스에 직접 노출하지 않고 각자 공개한 API를 통해서만 접근할 수 있다(정보은닉), 또한 저장소가 격리돼 있기 때문에 데이터를 통한 변경의 파급 효과(영향도)를 줄여 서비스를 독립적으로 만든다.

그러나 이처럼 마이크로서비스별로 기능을 분리하고 저장소를 격리함에 따라 이전에는 불거지지 ㅇ낳았던 문제가 생긴다. 즉, 여러 개의 분산된 서비스에 걸쳐 비즈니스 처리를 수행하는 경우 비즈니스 정합성 및 데이터 일관성을 어떻게 보장할 것인가에 대한 문제다.

 

분산 트랜잭션 처리 패턴

손쉽게 적용할 수 있는 방법 중 한 가지는 여러 개의 분산된 서비스를 하나의 일관된 트랜잭션으로 묶는 것이다. 분산 트랜잭션 처리를 위한 전통적인 방법으로 2단계 커밋 같은 기법이 있다. 2단계 커밋은 분산 데이터 환경에서 원자성을 보장하기 위해 분산 트랜잭션에 포함돼 있는 모든 노드가 커밋되거나 롤백하는 매터니즘이다.

그러나 이 방법은 각 서비스에 잠금(lock in)이 걸려 발생하는 성능 문제 탓에 효율적인 방법이 아니다. 특히 NoSql저장소에서는 2단계 커밋을 지원하지 않기 때문에 NoSql이 포함되어 있다면 사용할 수 없다.

마이크로서비스 독립적인 분산 트랜잭션 처리를 지원하는 패턴이 바로 사가(Saga) 패턴이다.

사가 패턴은 각 서비스의 로컬 트랜잭션을 순차적으로 처리하는 패턴이다. 사가 패턴은 여러 개의 분산된 서비스를 하나의 트랜잭션으로 묶지 않고 각 로컬 트랜잭션과 보상 트랜잭션을 이용해 비즈니스 및 데이터의 정합성을 맞춘다.

밑에 그림과 같이 각 로컬 트랜잭션은 자신의 데이터베이스를 업데이트한 다음, 사가 내에 있는 다음 로컬 트랜잭션을 트리거하는 메시지 또는 이벤트를 게시해서 데이터의 일관성을 맞춘다.

출처 : https://engineering-skcc.github.io/microservice outer achitecture/inner-architecture-saga/

 

 

롤백은 어떻게 할까? 사가는 일관성 유지가 필요한 트랜잭션을 모두 묶어 하나의 트랜잭션으로 처리하지 않고, 각 로컬 트랜잭션으로 분리해서 순차적으로 처리하는 방법이다. 그러다가 트랜잭션이 실패한 경우 이전 로컬 트랜잭션이 작성한 변경 사항을 취소하는 일련의 보상 트랜잭션을 통해 비즈니스 처리의 일관성을 유지한다.

하나의 업무를 예로 들어 살펴보자. 아래 그림을 보면 주문 서비스와 고객 서비스가 있다. 그리고 주문을 처리할 때 고객의 신용한도 정보에 따라 최종 주문을 승인하는 업무가 있다. 이 두 서비스의 트랜잭션을 하나로 묶지 않고 보상 트랜잭션과 이벤트를 활용해 처리할 수 있다.

 

출처 : https://engineering-skcc.github.io/microservice outer achitecture/inner-architecture-saga/

 

  1. 주문 처리가 시작되면 주문 서비스는 가주문을 생성하고 주문자 정보가 담긴 '주문 생성됨' 이벤트를 발행하고 트랜잭션을 종료한다.
  2. 고객 서비스가 '주문 생성됨' 이벤트를 확인한 뒤 다음 처리를 수행한다.
    1. 이벤트에 존재하는 주문자 정보로 고객의 신용한도를 조회해서 신용한도가 충족되면 '신용 승인됨' 이벤트를 발생한다.
    2. 신용한도가 충족되지 않는다면 '신용한도 초과됨' 이벤트를 발행한다.
  3. 주문 서비스는 고객 서비스가 발행한 이벤트를 확인해 다음 처리를 수행한다.
    1. 고객 서비스가 발행한 이벤트가 '신용 승인됨'인 경우에는 주문 승인 처리를 한다.
    2. '신용한도 초과됨' 이벤트인 경우에는 보상 트랜잭션인 주문 처리 취소를 수행한다.

 

 

데이터 일관성에 대한 생각의 전환: 결과적 일관성

이전까지는 데이터의 일관성이 실시간으로 반드시 맞아야 한다는 생각이 일반적이었다. 그렇지만 과연 모든 비즈니스 규칙들이 실시간으로 일관성을 맞춰야 할까? 정말 그래야 하는가는 생각해 볼 문제이다.

쇼핑몰에서 주문을 하면 결제 처리가 돼야 하고 그 결제가 완료되면 결제 내용과 주문 처리 내역이 주문자에게 이메일로 전송돼야 한다. 하지만 주문자가 많아 폭주한 경우를 생각해보자. 수만 개의 주문이 발생하는데 결제 서비스에서 타사 외부 연동 장애가 발생해 더는 주문을 받을 수 없는 상황이 발생할 수도 있다. 따라서 이러한 상황을 고려했을 때 비즈니스 관점에서 보면 주문과 결제, 이메일 전송을 순차적으로 처리하기보다 무조건 먼저 주문을 많이 받아 놓는 것이 좋을 수 있다.

모든 비즈니스는 실시간을 요구하는 것은 아니다. 어떤 비즈니스는 데이터의 일관성이 실시간으로 이뤄지지 않더라도 어느 일정 시점이 됐을 때 일관성을 만족해도 되는 것이 잇다. 이러한 개념을 결과적 일관성(eventual consistency)라고 한다.

 

출처 : https://engineering-skcc.github.io/microservice outer achitecture/inner-architecture-saga/

 

  1. 가주문이 생성되고 '가주문됨' 이벤트를 발행한다. 주문은 독립적 로컬 트랜잭션이기 때문에 끊임없이 받을 수 있다. 주문이 몰릴 경우 주문 서비스만 확장해서 가용성을 높일 수 있다.
  2. '가주문됨' 이벤트는 메시지 브로커에 비동기로 전송된다.
  3. 결제 서비스는 발행된 '가주문됨' 이벤트를 확인하고 대금 결제 트랜잭션을 수행하고 '결제 처리됨' 이벤트를 확인한다.
  4. 이메일 서비스는 '결제 처리됨' 이벤트를 확인하고 주문 결제 완료 이메일을 사용자에게 발송한다.
  5. 주문 서비스는 '결제 처리됨' 이벤트를 확인하고 주문 결제 완료 이메일을 사용자에게 발송한다.
  6. 이메일 서비스는 주문 서비스가 발행한 '최종 주문 완료됨' 이벤트를 확인해 최종적으로 주문이 완료됐다는 이메일을 사용자에게 발송한다.
  7. 각 서비스는 각기 작업을 수행하다 오류가 발생하면 '실패 이벤트'를 발행해 다른 서비스가 비즈니스 정합성을 맞출 수 있게 한다.
  8. 이때 별도로 메시지 큐에 쌓이는 이벤트들을 모니터링 서비스와 연계해 모니터링하고 추적해서 전체적인 비즈니스 정합성 여부를 관리자가 확인할 수도 있다.

 

 

읽기와 쓰기 분리: CQRS 패턴

서비스의 서능 향상을 위해 서비스 인스턴스를 스케일 아웃해서 여러 개로 실행한 경우 데이터 읽기/수정 작업으로 인한 리소스 교착상태가 발생할 수 있다.

이 문제를 해결하는 방법이 CQRS패턴인데 Command Query Reponsibility Segregation 즉 명령 조회 책임 분리를 의미한다. 기존의 일반적이었던 동일한 저장소에 데이터를 넣고 입력, 조회, 수정, 삭제를 모두 처리하는 방식에 도전하는 방식이다.

일반적인 비즈니스 모델에서는 입력, 수정, 삭제가 조회보다 적게 쓰이고 조회 요청이 훨씬 많이 사용된다. 그런데 서비스 내에 이러한 모든 기능을 넣어 두면 조회 요청 빈도가 증가함에 따라 다른 명령 기능도 함께 확장해야 하므로 효율적이지 않다.

따라서 저장소에 쓰기 모델과 읽기 모델을 분리하는 방식으로 변화시켜 쓰기 서비스와 조회 서비스를 분리할 수도 있고, 더 나아가 아예 물리적으로 쓰기 트랜잭션용 저장소와 조회용 저장소를 따로 준비할 수 있다.

API 조합과 CQRS

'주문 이력' 서비스는 제품 서비스가 제공하는 제품 정보, 주문 서비스의 주문 정보, 고객 서비스의 특정 고객 정보, 배송 서비스의 배송 정보가 모두 다 필요하다. 따라서 각 기능을 제공하는 마이크로서비스를 조합하는 상위 마이크로서비스를 만들어 조합된 기능을 제공할 수 있다.

그렇지만 이러한 구조는 상위 서비스가 하위 서비스에 의존하는 결과를 가져온다. 하위 서비스 중 하나라도 실패할 경우 상위 서비스에 영향을 준다.

다른 방법으로는 주문 이력 서비스를 제공하는 마이크로서비스가 독자적인 저장소를 갖도록 만든다. 원청 정보를 보여한 서비스에서 정보가 변경되는 순간 그 내역을 이벤트로 발생시켜 주문 이력서에 내용을 공유하여 준다.

 

출처 : https://engineering-skcc.github.io/microservice outer achitecture/inner-architecture-cqrs/

 

 

 

2.5 정리

MSA 아키텍처 흐름과 MSA 아키텍처를 이루는 구성요소와 주요 패턴들을 살펴봤다.

  • 현대 애플리케이션 아키텍처에 대해 요구하는 특성을 알아보기 위해 리액티브 선언을 살펴보면 주요 특성으로 응답성, 유연성, 탄력성, 메시지 기반 등이 요구된다는 것을 알 수 있다. 특히 이러한 요소들은 애플리케이션의 유연성을 강하게 요구한다.
  • MSA 아키텍처는 기존의 벤더 중심의 강 결합 아키텍처에서 오픈소스 중심의 느슨한 결합의 아키텍처로 변화할 것을 요구한다.
  • MSA 아키텍처는 마이크로서비스 외부의 구성을 위한 외부 아키텍처와 마이크로서비스 내부 정의를 위한 내부 아키텍처로 구성된다.
  • MSA 아키텍처 영역의 문제 해결 방식이 다양한 MSA 패턴으로 정리되고 있고, 인프라 구성요소, 플랫폼 운영 관리 패턴, 애플리케이션 연계와 관련된 패턴 등이 존재한다.
  • 클라우드 인프라 구성요소로 가상 머신, 컨테이너, 컨테이너 오케스트레이션 등이 고려된다.
  • 마이크로서비스의 생태계 발전과 함께 마이크로서비스 운영 관리를 위한 플랫폼 패턴들이 탄생했다.
  • 플랫폼 패턴으로 넷플릭스OSS 기반의 애플리케이션을 활용한 패턴이 최초로 등장했고, 이를 발전시킨 패턴이 쿠버네티스, 이스티오 등의 기술로 발전해 오고 있다.
  • 마이크로서비스 애플리케이션을 구성하고 연계하기 위해 UI컴포지트, 통신 패턴, 이벤트 기반 아키텍처 등이 고려된다.
  • 저장소 분리 등으로 인한 분산 트랜잭션의 근본적인 문제 등을 해결하기 위해 사가 패턴, CQRS, 이벤트소싱 패턴 등이 고려된다.

 

http:// http://www.kyobobook.co.kr/product/detailViewKor.laf?ejkGb=KOR&mallGb=KOR&barcode=9791158392468&orderClick=LEA&Kc=

반응형