https://waspro.tistory.com/718

  • RESTFul API가 적용된 프로젝트
  • 독립적인 배포가 가능하도록 결합도를 낮춘 프로젝트
  • 클라우드가 적용된 확장성, 가용성이 확보된 프로젝트
  • 자동화된 배포 체계가 갖추어진 프로젝트
  • DevOps 조직 체계를 적용한 프로젝트


"마이크로서비스 아키텍처는 그간 IT를 이끌어온 아키텍처 사상들의 Pain Point들을 수집하고 이를 어떻게 해소해 낼 것인가에 집중한 아키텍처 사상이며, 고객의 니즈를 신속하게 적용하기 위해 여러 기술셋들을 선택적으로 적용한 아키텍처이다. 성공적으로 전환한 프로젝트는 바로 이를 달성한 프로젝트라 할 수 있다."

여기서 주목해야 하는 점은 기술 적용이 아니라... Pain Point를 해소하기 위한 기술셋들을 선택적으로 적용한이다.

마이크로서비스 아키텍처는 기술셋에 의존된 설계 방식이 아닌 반대로 목표를 수립하고 달성하기 위해 기술셋을 선택하는 방식으로 접근해야 한다는 것이다. 이와 같은 접근 방식이 있어야 다양한 오픈소스 소프트웨어의 적용여부를 검토하고 프로젝트에 적합한 개발방식 등을 선택해 낼 수 있을 것이다.

 

모놀리식 어플리케이션에서 마이크로서비스 아키텍처로의 전환은 BIG BANG 방식으로 전환하는 TOP DOWN 방식을 여전히 선호하는 것이 국내 프로젝트의 실정이지만, 아키텍처 사상의 변화는 거버넌스(관리) 측면은 물론 어플리케이션의 구조적인 변화가 크게 발생하기 때문에 옳바른 전환 방식이라 할 수 없다.

 

리스크를 최소화하며 마이크로서비스로 전환해 나가기위해서는 백엔드 → 데이터베이스(데이터) → 프론트엔드 순으로 점진적인 변화를 가져가는 것이 효과적이다.

 

 

먼저 백엔드 어플리케이션을 마이크로서비스로 전환하는 과정에 대해 간단히 살펴보자.
"아키텍트는 서비스 단위를 결정하기 위해 Bounded Context를 적용하여 서비스 범위를 정의하고, 그 기준에 따라 서비스가 결정되면, 서비스간 인터페이스 방식을 결정하며, 인터페이스를 위한 기술셋을 선택한다. 개발자는 API를 식별하고, 인터페이스에 필요한 기술요소들을 활용하여 개발한다."
이때 마이크로서비스 전환이 시작되는 시점부터 반드시 데이터베이스를 분리해야 하는가? 라는 질문이 있을 수 있다. 결론부터 말하자면 반드시 초기부터 데이터를 구분할 필요는 없다. 물론 장기적인 관점에서 바라보았을때, 점진적 이행이 가능한 형태로 데이터베이스를 분리해 나가는 것은 중요하지만, 초기 마이크로서비스 아키텍처를 적용하여 프로젝트를 시작하는 시점에서 데이터베이스를 분리하는 것은 위험도가 굉장히 높아 질뿐 아니라, 프로젝트 실패시 부담해야할 리스크 역시 커질 수 있다.
MSA 방법론, 모델링, 분석/설계, 개발, 테스트, 이행을 거치며, 마이크로서비스의 단위는 유동적으로 변화할 수 있다. 어플리케이션 영역(화면, 백엔드)에서는 변화에 따라 대응 개발하기 용이하지만, 데이터의 재배치, 테이블의 재설계는 어플리케이션 전체에 영향을 끼칠 수 있는 영역으로 재설계가 용이하지 않고 데이터의 변화에 따라 어플리케이션 구조 변화에 큰 영향을 주게된다. 따라서 Persistent의 경우 백엔드 서비스의 전환이 완료되거나, 안정화 된 이후에 설계하는 것이 좋고, 특히나 빅뱅방식의 전환은 지양해야 한다.

MSA로의 전환을 이야기할때, MINISERVICE가 함께 등장하는 이유 역시 이와 같으며, 성공적인 전환을 위해 프로젝트는 장기간 점진적인 변화 구조를 가져가는 것이 무엇보다 중요하다.
지금부터는 본격적으로 DB가 분리된 마이크로서비스와 서비스만 분리된 마이크로서비스 간의 차이점을 알아보고, 점진적이행을 위해 고려되어야 할 부분에 대해 알아보도록 하자.

아키텍처의 변화

제일 먼저 살펴보아야 할 부분은 바로 아키텍처의 변화 측면이다. 데이터베이스의 분리는 인프라 아키텍처, 어플리케이션 아키텍처 측면에서 커다란 변화를 불러일으킨다. 이를 하나씩 살펴보도록 하자.

인프라 아키텍처

인프라 아키텍처 측면에서 가장 고려되어야 할 부분은 바로 구조의 변화 측면이다.

각 마이크로서비스 별로 독립적인 데이터베이스를 구성할 경우 아래와 같은 사항에 주의해야 한다.

  • 비용 : 데이터베이스의 물리적 노드 증가에 따른 비용 증가. 오픈소스 DB를 사용할 경우 구축/운영 인력 증가.
  • 성능 : 호출 홉 증가에 따른 성능 저하. 데이터 전송에 따른 성능 저하.
  • 인력 : 기술셋 확장에 따른 지원인력 증가.
  • 모델링 : 마이크로서비스 인터페이스 모델링, 데이터베이스 모델링(테이블 분할 설계/데이터 오너쉽 정의 등)

어플리케이션 아키텍처

어플리케이션 아키텍처 측면에서 가장 고려해야 할 부분은 바로 서비스 간 데이터의 동기화 측면이다.

각 마이크로서비스 별로 독립적인 데이터베이스를 구성할 경우 아래와 같은 사항에 주의해야 한다.

  • 조인쿼리 : 모놀리식 어플리케이션 내 조인쿼리에 대응하기 위한 동기/비동기 처리 호출 설계.
  • 트랜잭션관리 : 분산트랜잭션 관리를 위한 이벤트 처리 설계.
  • 보상트랜잭션 : 데이터 복구를 위한 Saga 패턴 설계
  • API 증가 : 데이터 호출 증가에 따른 API 설계.
  • 배치 : 배치 아키텍처 설계를 위한 데이터 통합 방안 설계.

개발의 변화

앞서 정의한 인프라/아키텍처의 변화는 그 지향점을 명확히 파악하고 대체할 수 있다. 물론 비용/시간/일정/인력의 변화를 감수한다면 말이다. 그러나, 개발의 경우 DB의 분리로부터 어떠한 영향이 발생할 것인지 파악하는 것은 굉장히 어려운 일이다.
분석/설계를 진행하며, API 목록을 도출하고, 동기/비동기 서비스로 구분하여 어플리케이션 구조를 개선해야 나가야 한다. 인터페이스의 증가에 따른 비용/일정 그리고 무엇보다 리스크를 감내해야 하고 데이터베이스 분리에 따른 테이블/테이터 설계 측면에서도 고려해야 한다.
무엇보다 단일 데이터베이스의 조인쿼리에 대해 API Composition, CQRS 테이블 생성 특히 보상 트랜잭션에 대한 설계 등은 단순히 개발 본수의 증가만을 이야기 하는 것이 아니라, 개발자가 설계에 참여하여 개발의 방향성을 결정해야 하는 문제들도 당면하게 된다. 물론 DevOps 조직이 갖춰진 플랫폼 기업의 경우 이미 그렇게 진행되고 있겠지만, 대부분의 SI 프로젝트를 발주하는 기업들의 경우 조직의 변화가 갖추어졌을리 만무하다.
또한, 테이블 재설계는 물론 데이터 오너쉽 정의, 배치처리 업무, 서비스 연관도 분할, MSA 비 대상 서비스와의 결합도 약화, 인터페이스 개발, 비즈니스 개선, 프로세스 개선 등 개발에서 확장된 업무들이 개발자의 역할로 부여 받게 된다.
이로 인해 개발자는 정확한 공수 산정 및 개발에 필요한 기술셋, 일정 등을 사전에 파악하기 어려워 무엇보다 개발 PL의 역할이 중요해진다.

결론

마이크로서비스 아키텍처를 설명하는 기술셋에서 DB의 분리는 비즈니스 요건에 따라 명확히 구분하고 접근해야 한다. 무조건 모든 서비스를 분리하는 것은 인프라 측면, 어플리케이션 측면에서 많은 기회비용을 지불해야 하기 때문이다.
비즈니스 요구사항 중 서비스 독립성/확장성이 강조되는 경우 요소 별 투입되는 아키텍처 기반 비용을 감안하여 분리 가능여부를 결정해야 한다. 초기 거론한것 처럼 점진적 이행을 위해 기반 환경을 구성하고 리스크 감소 차원에서 데이터베이스 분리는 서비스 별 점진적으로 확대해 나가는 것이 올바른 방향이라 할 수 있다.
간혹 마이크로서비스 당 하나의 데이터베이스를 반드시 구성해야 한다는 강박관념으로부터 마이크로서비스를 설계하는 경우가 있다. 데이터베이스를 구분하는 것은 단순히 물리적인 공간을 구분하는 것이 아닌 데이터의 정합성, 연속성을 보장하기 위해 많은 노력과 비용이 발생하는 아키텍처 패턴임을 명심해야 한다. 불필요하게 보상 트랜잭션 처리하고, 비동기 서비스를 호출하는 것은 결과적으로 이행/오픈/유지보수 전 과정에 걸쳐 추가적인 Effort를 발생시키는 일임에는 분명한 사실이다.
그럼에도 불구하고 결합도를 낮추고 신속한 배포가 가능하다는 점에서 DB의 분리를 통해 얻을 수 있는 장점 또한 굉장히 크다. DB 분리를 통해 얻을 수 있는 장점과 기회비용을 판단하여 비즈니스 요구사항을 달성하기 위해 점진적인 이행 로드맵을 수립해나감으로써 성공적인 MSA 전환 사례를 만드는것이 무엇보다 중요하다는 점을 기억하고 이번 포스팅을 마치고자 한다.

'프로그래밍 > MSA' 카테고리의 다른 글

SAGA 보상 트랜잭션  (0) 2023.05.19
분산 트랜잭션 관리(Saga Pattern)  (0) 2023.05.19
MSA 기술 트렌드 2022  (0) 2021.12.27
MSA Observer Service Pattern  (0) 2019.05.21

펌 : https://waspro.tistory.com/603

 

SAGA 패턴 & 보상트랜잭션

SAGA 패턴은 서비스 별 각 트랜잭션이 단일 서비스 내의 데이터를 갱신하는 일련의 로컬 트랜잭션을 의미한다. 첫번째 서비스의 트랜잭션이 완료되면 두번째 서비스의 트랜잭션이 동작하도록 트

waspro.tistory.com

SAGA 패턴은 서비스 별 각 트랜잭션이 단일 서비스 내의 데이터를 갱신하는 일련의 로컬 트랜잭션을 의미한다.

첫번째 서비스의 트랜잭션이 완료되면 두번째 서비스의 트랜잭션이 동작하도록 트리거 되는 방식이라 생각할 수 있다.

SAGA 패턴은 크게 두가지 방식으로 구현할 수 있다.

  • Event / Chreography : 각 로컬 트랜잭션이 이벤트를 발생시키고, 다른 서비스가 트리거 하는 방식
  • Command / Orchestration : 오케스트레이터가 어떤 트랜잭션을 수행할 건지 알려주는 방식

그럼 각 방식에 대해 간단히 살펴보자.

Event/Chreography

각 서비스 마다 자신의 트랜잭션을 관리하며 현재 상태를 변경한 후 이벤트를 발생시키고, 그 이벤트를 다른 서비스에 전달하는 방식으로 트랜잭션이 처리된다.

 

결과 값 또한 잘 진행되지 않았을 시에는 보상 트랜잭션을 통한 보상 이벤트를 발생시켜 관리된다.

 

각 트랜잭션마다 공통된 공유 ID를 정의하는 것이 중요하므로 Event를 던질 때 마다 모든 Listener가 참조하는 트랜잭션을 확인할 수 있다.

물건을 주문하기 위한 과정을 설명하고 있다. Order, Payment, Socket, Delivery 서비스는 하나의 마이크로서비스 형태의 독립된 형태로 관리되며 각 서비스를 개별 트랜잭션을 관리한다.

 

각 서비스는 자신의 트랜잭션이 성공적으로 완료되면 다음 서비스를 호출하기 위한 Trigger를 동작시킨다. 이 또한 하나의 이벤트 형태로 동작하며, 다음 서비스를 동작하게 하는 역할을 담당한다.

각 트랜잭션은  독립적으로 동작하기 때문에 트래잭션이 완료된 경우의 해당 트랜잭션을 롤백하기 위해서는 이전 서비스로 돌아가야 한다.

동일한 프로세스가 진행된다고 할 때 Stock Service에서 재고를 확인하는 도중 해당 상품이 매진 된 것을 확인했을 때는 이러한 동작을 하게 된다.

이미 개별 트랜잭션이 완료된 서비스는 Order, Payment 두 서비스가 있다.

Stock Service는 현재까지 처리가 완료된 서비스를 알고 있어야 하며, 정보를 기반으로 해당 서비스의 Rollback을 요청하게 된다.

 

이는 각 마이크로서비스의 롤백 프로세스가 처리되어 Commit된 정보를 이전 상태로 돌린다.

 

이와 같은 방식은 구현이 복잡하지 않아(완료된 서비스 정보, 다음 서비스 요청을 위한 트리거) 쉽게 개발하고 배치할 수 있으나, 서비스 간 호출 흐름을 인지하는 ID를 관리해야 하며, 모든 서비스는 Trigger에 의해 동작할 수 있도록 각 서비스 이벤트를 리슨하고 있어야 한다.

Command/Orchestration

오케스트레이터가 전체 서비스에 명령을 날리며, 명령을 중계하는 브로커(MessageQueue)를 사용한다. 이때 전송 채널은 각 서비스 별로 할당하지만, 결과를 확인하는 Reply 채널을 두어 서비스 성공 또는 실패에 대한 처리 방안을 마련한다.

각 명령에 해당하는 상태 시스템을 가지고 있고, 이 상태 시스템을 통해서 전체 트랜잭션의 상태를 파악하기 쉽기 때문에 테스트하기도 쉽다.

모든 흐름은 Order Saga Orchestrator에 의해 동작한다. 서비스 별 트랜잭션을 직접 관리하고, 성공, 실패에 따른 동작 방식 역시 오케스트레이터가 직접 관리한다.

만약 이와 같은 형태에서 트랜잭션 실패가 났을 경우를 살펴보자.

위와 같이 주문한 서비스의 Stock이 부족할 경우의 처리 과정이다.

1) Stock Service는 재고를 확인했더니 부족하여 이를 Reply Channel을 통해 Saga Orchestrator에게 전달한다.

2) Orchestrator는 환불을 위한 Payment Channel을 생성하여 Payment Service에게 전달한다.

3) Payment Service는 환불을 진행하고 클라이언트에게 알림을 발송한다.

위와 같이 Chreography 방식은 서비스 간 종속성이 없어 서비스 간 보다 독립된 서비스 구축이 가능하며, 서비스 복잡도가 감소한다. 또한, 테스트가 쉽고 롤백을 쉽게 관리할 수 있다.

다만 모든 트랜잭션 관리는 오케스트레이터가 관리하여 오케스트레이터의 관리와 네트워크 Hop이 증가할 수 있으며, 인프라가 다소 복잡하게 구성될 수도 있다.

'프로그래밍 > MSA' 카테고리의 다른 글

MSA의 성공 기준  (0) 2023.05.19
분산 트랜잭션 관리(Saga Pattern)  (0) 2023.05.19
MSA 기술 트렌드 2022  (0) 2021.12.27
MSA Observer Service Pattern  (0) 2019.05.21

MSA의 비지니스 도메인 간에 종속성을 없앨 수 있는 Observer Service Pattern

 

예를 들어 상품의 상태(재고, 판매상태 등)가 변하면 상품 뿐만 아니라, 검색, 전시, 물류 등 여러 비지니스 로직을 처리해야 하는 경우

  • 특정 도메인의 상태 변경으로 인해 타 도메인의 서비스를 연속적으로 호출해야 하는 경우 

  • 비지니스 복잡도가 증가할수록 상태 변경을 처리하는 로직에서 해야할 일이 많아지고, 소스 코드는 복잡해 지며,
    종속성 증가, 트랜잭션 시간 증가, 교착상태 발생(deadlock) 등 다양한 문제가 생긴다.

 

[도메인에서 상태 변경 처리]

  • 도메인 자신의 상태 변경만 처리한 후 메시지 큐에 상태 변경을 등록한다.
  • 즉, 자기 자신의 비지니스 로직 처리만 집중하며, 상태 변경에 따른 다른 도메인의 영향 범위 처리는 모두 Message Queue(MQ)에 일임한다.

[Observer 등록]

  • 특정 도메인의 상태 변경에 영향을 받는 비지니스가 있으면, MQ에 Observer 등록을 한다.

 

[Receive Message]

  • MQ는 Queue에 들어온 메시지를 각 Observer에게 전송(또는 Observer가 polling) 한다.
  • 각 Observer에서 메시지 처리가 완료되면, 메시지 삭제를 위한 신호를 MQ에 보낸다.

 

 

위와 같이 Observer Service 패턴을 이용하는 경우 도메인의 종속성(Dependency)을 끊을 수 있으며, 

Observer Service 에 메시지를 전송하는 부분을 AOP로 제공하면, 도메인은 비지니스 로직의 처리에 집중할 수 있다.

 

[주의사항]

  • 본 패턴은 비동기 처리가 가능한 비지니스, 즉, 데이터 정합성이 높지 않은 비지니스에 적합할 것임 

 

'프로그래밍 > MSA' 카테고리의 다른 글

MSA의 성공 기준  (0) 2023.05.19
SAGA 보상 트랜잭션  (0) 2023.05.19
분산 트랜잭션 관리(Saga Pattern)  (0) 2023.05.19
MSA 기술 트렌드 2022  (0) 2021.12.27

+ Recent posts