본문 바로가기
IT정보&정보처리기사

마이크로서비스 아키텍처의 데이터베이스

by Technocrat 2024. 3. 8.

마이크로서비스의 서비스들은 모델(비즈니스 데이터)를 보유한다. 서비스는 자신이 소유하지 않는 모델에 접근하기 위해 해당 모델을 소유한 서비스를 거쳐야 한다. 여러 서비스가 하나의 데이터베이스를 공유하면서 직접 접근하는 것은 권장하지 않는다. 데이터베이스 변경 시 변경되는 서비스의 범위가 확대되기 때문이며 이는 마이크로서비스 아키텍처의 신속하고 유연한 애플리케이션 개발, 운영 목적에 부합하지 않는다. 따라서 서비스와 모델이 일대일 관계가 되도록 구성해서 데이터베이스 변경이 필요한 경우 바로 대응할 수 있도록 한다.

 

 

트랜잭션을 설계 시 원칙적으로 로컬트랜잭션을 권장한다. 로컬 트랜잭션은 하나의 트랜잭션 컨택스트 내에 처리 대상 리소스를 제한하는 것이다. 즉 프로그램 소스코드에서 begin과 commit으로 구분된 하나의 트랜잭션에서 하나의 데이터베이스만을 처리대상으로 한다면 해당 트랜잭션은 로컬 트랜잭션이다.  마이크로서비스에서는 각 서비스가 하나의 데이터베이스를 소유하고 트랜잭션 컨택스트 내에서 해당 데이터베이스만 대상으로 처리하는 로컬 트랜잭션을 기본으로 한다. 

하나의 트랜잭션 컨택스트 안에 여러 리소스를 포함하는 경우를 글로벌트랜잭션이라고 한다. 글로벌트랜잭션은 분산 트랜잭션 구조를 사용하여 구현한다. Two-Phase commit 등의 프로토콜을 활용해 분산트랜잭션을 구현한다.

예를들어 온라인 쇼핑에서 주문 데이터베이스의 주문 레코드 삽입과 재고 데이터베이스의 재고 준비를 하나의 트랜잭션으로 처리하는 경우 글로벌트랜잭션이 된다. 글로벌 트랜잭션은 운영하기가 까다롭다. 지속적인 변화에 유연하고 단순함을 추구하는 마이크로서비스 아키텍처는 컴포넌트 간 느슨한 결합을 추구하기에 글로벌트랜잭션은 방해가 된다.

 

마이크로서비스 아키텍처에서  데이터베이스간 동기화를 이루는 방법은 사가(Saga)가 있다. 사가는 로컬트랜젝션, 이벤트, 보상 트랜잭션 등의 기법을 사용하여 여러 리소스 간 동기화를 이루는 디자인 패턴이다. 

아래 그림 처럼 사가패턴에서는 트랜잭션 처리를 진행할 때 이벤트 릴레이를 통해 로컬트랜잭션들을 연계한다. 최초 데이터베이스 변경이 성공하면 메시징 구조를 이용해 이벤트를 전달하고 다음 서비스가 이벤트를 받아서 자신의 데이터베이스를 변경한다. 만일 특정 단계에서 데이터베이스변경을 실패한 경우 장애 발생 이전의 데이터베이스 상태로 되돌리는 이벤트를 반대방향으로 릴레이하는데 이를 보상 트랜잭션이라고 한다. 

 

 

 

 

사가패턴은 특정시점에서 데이터베이스의 일관성이 유지되지 않을 수 있다. 따라서 데이터베이스의 일관성이 엄격하게 유지되어야 할 경우 사용할 수 없다. 어느정도의 시간이 경과한 후 결과적으로 일관성을 유지해도 되는 경우 사용된다.

 

분산 데이터베이스 환경에서 여러 데이터베이스에 나누어져 있는 데이터를 하나의 뷰로 구성해서 클라이언트에게 제공하기 위한 방법은 두 가지가 있다. 첫번째는 API컴포지션이다.

API컴포지션은 도메인 계층의 집약 서비스와 인프라 계층의 리포지터리 서비스를 통해 여러개의 데이터베이스로부터 얻은 데이터를 애플리케이션 계층에서 인메모리로 결합하는 디자인 패턴이다. API컴포지션은 직관적이고 설계 및 구현이 용이하다. 다만 메모리 내 결합이기에 시스템 리소스에 부담을 주어 성능 및 확장성에 부정적이다.

 

 

두번째 방법은 CQRS&이벤트소싱이다. 이 방법을 통해 데이터 결합 뿐 아니라 결과적인 일관성을 구현할 수도 있다.

 CQRS(Command Query Responsibility Segregation, 명령 질의 책임 분리)란 데이터 접근 처리를 갱신형 처리(명령)와 참조형 처리(질의)로 구분하고 각각을 구현하기 위해 독립된 서비스 컴포넌트와 데이터 저장소를 두는 디자인 패턴이다. 

 

일반적으로 참조형 처리는 요청량이 많아 빠른 응답을 요구한다. 반면 갱신형 처리는 요청량은 많지 않지만 안전하고 확실한 트랜잭션 완료가 요구된다. 갱신형 처리에는 트랜잭션 기능과 신뢰성이 높은 영구적 데이터 저장소를 만들고 참조형 처리에는 고속 검색 기능을 가진 데이터스토어를 만들어 배치한다.

갱신형 저장소와 참조형 저장소 간 동기화는 이벤트소싱을 통해 구현한다. 

기존의 비즈니스 데이터 처리는 비즈니스 처리를 분할해서 각각의 데이터 저장소에 저장하고 데이터 동기화를 위해 글로벌 트랜잭션을 사용한다. 예를 들어 한건의 주문 처리를 주문과 재고로 분리하여 주문은 주문 데이터베이스에 재고처리는 재고 데이터베이스에 각각 저장한다. 이벤트 소싱은 비즈니스 데이터를 분리하지 않고 모아서 하나의 데이터 저장소에 저장한다. 이 데이터 저장소를 이벤트 소스라고 한다. 모든 비즈니스 이력이 하나의 이벤트 소스에 저장되므로 비즈니스 감사 데이터로 활용이 가능하다. 그러나 이러한 장부는 이력저장에는 좋지만 검색이 느려진다. 따라서 이벤트 소싱에서는 검색용 데이터 스토어를 만들어 메시징 기반 미들웨어(Messaging Oriented Middleware, MOM)의 비동기 메시징을 사용하여 이벤트 소스와 검색용 데이터 저장소를 동기화한다. 동기화의 시점은 조절 할 수 있다.