Angeliot

마이크로서비스 - 데이터 조인하기

September 19, 2018 | 3 Minute Read

Join은 서비스에서 반드시 필요한 연산입니다. 하지만 DB가 분리된 마이크로서비스에서는 쓸수가 없습니다. 맵리듀스와 같은 데이터 프로세싱 방법은 기본적으로 DB의 분리를 가정하여 만들어진 시스템이나 조회 서비스 용도에는 부적합합니다. 우리가 선택할 수 있는 방법에 대해 알아봅시다.

SELECT orders.date, orders.quantity, items.name FROM orders INNER JOIN items ON orders.itemId = items.id

데이터 저장의 독립성

이 부분은 마이크로서비스로 전환할때 왜 데이터 베이스를 서비스 오너십에 따라서 나눠야하는지 설명하는 부분입니다. 필요 없다면 다음 파트로 넘어가도 됩니다.

Monolithic 아키텍처에서는 하나의 거대한 DB를 사용합니다. 서비스 - DB 연결이 Many to One 구조입니다. 하지만 마이크로서비스에서는 One to One 구조입니다. 다양한 서비스들이 하나의 DB에 연결되면 다음 두가지의 문제 현상이 발생합니다.

  1. DB를 바꾸는것이 너무 고통스럽다.
  2. 서비스를 안쓰고 DB를 쓴다.

전통적인 RDBMS는 데이터의 안전한 저장을 목표로하기 때문에 업데이트가 빈번하거나 랜덤 읽기가 많을 경우에는 부적합합니다. 이 때문에 서비스 환경에 따라서 RDBMS와 NoSQL을 같이 사용합니다. 하지만 많은 서비스들이 하나의 DB를 쓸경우 서비스 중에 1%정도만 바꾸고 싶어도 나머지 99%를 신경써야하는 문제가 발생합니다. 주문과 상품 서비스가 있지만 /orders, /items에 GET요청 보다는 해당 테이블에 Select를 합니다. 서비스에 GET요청을 하여 데이터를 받을 경우 스키마가 달라져도 GET요청에 API 버전 정보를 추가하여 대응할 수 있지만 직접 Select하는 경우는 해당 테이블에 의존관계에 있는 모든 서비스에서 예외처리와 변경이 필요합니다. DB를 물리적으로 나누는것이 가장 좋으나 운영비용 때문에 어렵다면 최소한 Foreign Key같은 Constraint 라도 제거 하세요. Constraint를 쓸경우 테이블 간에 의존성이 강하게 생깁니다. 하나의 거대한 RDBMS를 사용한다면 다음과 같은 단계적 접근을 추천합니다.

  1. Foreign Key 제거
  2. Select 대신 해당 서비스 통해 조회, Select > Http Get
  3. DB 물리적 분리

2번까지만 달성하더라도 서비스가 굉장히 유연해지나 DB 물리적 분리까지 달성하면 더 굉장해집니다.

Join in Client Application

주문-상품의 조인 데이터가 필요하면 주문 조회, 상품 조회후에 어플리케이션에서 조인하자

Nginx

이 아이디어는 DB가 클러스터링을 아직 지원 안할때 부터 쓰던 오래된 방법입니다. 각각의 데이터를 조회한후에 데이터를 결합하고 이것을 리턴합니다. 이 방법은 데이터량에 따라서 쓸지 안쓸지 결정해야합니다.

  1. 작은 데이터 + 작은 데이터
  2. 큰 데이터 + 작은 데이터
  3. 큰 데이터 + 큰 데이터

2번까지만 적절한 방법입니다. 여러분의 서비스가 하루 10억건 요청/데이터 규모가 되기 전에는 충분히 유용한 방법이고 Monolithic > Microservice 전환중에도 유용한 방법입니다. 마이크로서비스가 JVM 기반으로 구현된 경우 GC를 조심해야합니다. DB에서 조인할경우 메모리 관리를 DB에서 하지만, 서비스 상에서 조인되기 때문에 GC량이 금방 차고 빈번하게 일어납니다.

Materialize The View

주문, 상품의 변경을 리스닝하여 주문-상품뷰를 구성하고 이것을 조회하자

Nginx

가장 좋은 방법이긴 하나 마이크로서비스가 Event Driven으로 전환이 끝나야 쓸수 있는 방법입니다. 마이크로서비스에서는 데이터가 변경되거나 생성될때마다 이벤트가 발생합니다. 이를 리스닝한다면 동일한 데이터 복사본을 얻을 수 있습니다. 이를 이용해서 조인된 데이터를 다루는 다른 서비스를 운영하는것입니다. 주문과 상품 데이터의 변경을 리스닝하는 주문-상품 서비스를 생성하고 주문과 상품 데이터가 변경될때 마다 주문-상품 조인 데이터를 업데이트합니다. 이후 이 데이터를 이용해서 서비스합니다. 마이크로서비스 디자인에서 클래스 디자인과 같이 Single Purpose가 1원칙 이기 때문에 조인 데이터를 다루는 추가 서비스를 생성해야합니다. 자주 나오는 실수가 별도의 서비스를 안생성하고 기존 주문 또는 성품 서비스에 인터페이스를 추가해서 사용하는것입니다.

주문 서비스는 주문 데이터만 다루고, 상품 서비스는 상품 데이터만 다루야하기 때문에 추가로 주문-상품 서비스를 생성해야합니다. 스키마 설계는 두가지 방법이 있습니다. 주문 데이터에 상품 ID를 피처로 두는 방법과 주문-상품 관계만 관리하는 스키마를 추가하는 방법입니다. 후자가 더 좋은 방법입니다. 전자의 경우 의존성을 가질때 마다 스키마가 변경되나 후자의 경우 의존성이 추가되면 의존성을 다루는 데이터만 추가하면되기 때문에 더 느슨한 연결이 됩니다.

참고자료

이미지 출처, Managing Data in Microservices https://www.youtube.com/watch?v=E8-e-3fRHBw

마이크로서비스 아키텍처에 대해 궁금한점이 있다면 포스트 하단의 링크(페이스북, 이메일)를 통해 문의주세요.