Microservice Query

개요

마이크로서비스로 전환 시 분산 데이터 관련 문제는 트랜잭션 뿐 아니라 쿼리를 구현하는 방법도 있다. DB가 하나뿐인 모놀리식 애플리케이션에서는 비교적 쉽게 쿼리를 구현했다. 하지만 마이크로서비스 아키택쳐에서는 여러 DB에 분산된 데이터를 조회해야 하는데, 기존 분산 쿼리 매커니즘은 기술적으로 가능해도 캡슐화에 위배되기에 부적절하다.

마이크로서비스 아키택쳐는 다음 두 패턴으로 쿼리를 구현한다.

  1. API 조합 패턴: 서비스 클라이언트가 데이터를 가진 여러 서비스를 직접 호출해 결과를 조합하는 간단한 방법
  2. CQRS 패턴: 커맨드 쿼리 책임 분산 패턴. 쿼리만 지원하는 하나 이상의 뷰 전용 DB를 유지하는 패턴

API 조합 패턴 응용 쿼리

모놀리식 애플리케이션은 전체 데이터가 하나의 DB에 있어 여러 테이블을 조인해서 주문 내역을 조회하면 되지만 마이크로서비스 아키택쳐로 전환하면 데이터가 여러 서비스에 흩어진다. 따라서 클라이언트가 모든 관련 서비스에 요청해야한다.

이 여러 서비스를 호출해 반환 결과를 조합하는 방법을 API 조합 패턴이라하고 다음과 같이 구성되어 있다.

이 패턴으로 특정 쿼리 작업을 구현할 수 있을지는 데이터의 여러 요인에 따라 가변적이다. 대부분의 경우는 이 패턴을 적용하여 쿼리 작업을 구현할 수 있다. 주문 애그리거트의 상세 정보를 쿼리한다고 하자. 클라이언트는 API 조합기의 REST endpoint로 요청을 보낼 것이다(gRPC 등 다른 IPC도 같은 개념). GET /order/{orderId}가 구현된 API 조합기는 해당 id로 각 관련 서비스를 호출한 후 수신응답을 EQUI 조인한다. 각 프로바이더 서비스는 애그리거트 하나에 해당하는 응답을 반환한다.

분산 시스템에서 쿼리 작업의 반응 시간을 최대한 줄이려면 가능한 한 API 조합기가 프로바이더를 병렬 호출해야한다. 하지만 동시에 병렬 호출할 수 있는 서비스가 아닌 의존 관계가 있어 순차 호출해야하는 경우도 있다. 이때 순차/병렬이 뒤섞인 호출을 성능/확장성이 우수하게 실행하려면 RxJava와 같은 리액티브 설계기법을 동원하는 것이 좋다.

API 조합 패턴의 단점은 다음과 같다.

  1. 오버헤드가 증가한다: 여러 서비스를 호출하고 여러 DB를 쿼리하는 오버헤드만큼 컴퓨팅/네트워크 리소스가 들고 운영 비용이 늘어난다.
  2. 가용성이 저하될 우려가 있다: 많은 서비스가 개입할 수록 전체 가용성은 떨어진다. 하나의 쿼리작업에 API 조합기 + 둘 이상의 프로바이더가 반드시 개입되는 구조라 하나로 처리하는것보다 가용성이 현저히 낮다. 프로바이더가 불능일 경우 조합기가 캐시데이터를 반환한다든지, 빼고 미완성 데이터를 반환한다든지 해서 가용성을 높일 수 있다.
  3. 데이터 일관성이 결여된다: 여러 DB대상으로 여러 쿼리를 실행하기 때문에 일관되지 않은 데이터가 반환될 수 있다.
  4. 인메모리 조인 시 효율성 저하: 데이터 양이 많을수록 효과적으로 쓰기 어렵다.