본문 바로가기
소프트웨어공학/Architecture

Multi datasource, router datasource

by 아이티.파머 2025. 1. 9.
반응형

멀티-테넌시란?

멀티-테넌시는 소프트웨어 어플리케이션의 단일 이느턴스가 여러 고객에게 서비스를 제공하는 아키텍처 이다.

아래 그림에서 보듯이 싱클 테넌시와 멀티테넌시는 확실하게 구분된다.

 

싱글테넌시의 경우 사용자 별로 어플리케이션과 Database 가 존재한다.

멀티테넌시의 경우엔 하나의 어플리케이션에서 여러 테넌트(tenant,사용자)가 사용할 수 있도록 해준다.

멀티테넌시를 구축하는 이유는 고객마다 새로운 시스템을 만들 필요가 없기 때문에 소프으웨어 개발과 유지보수 비용을 절약 할 수 있기때문에 경제 적이다.

멀티테넌시를 구축하는 방법은 여러 방법이 있다. 인프라 적인 부분, 소스코드에서 분기 혹은 database 에서 분리등 여러 방법을 이용하여 테넌트 분리가 가능 하며 대표적으로 다음과 같이 구분 해볼 수 있다.

  • 데이터베이스별 테넌트 (database-per-Tenant)
  • 스키마별 테넌트 (Schema-per-tenant
  • 테이블별 테넌트 (Row-level tenant)

단일 테넌시를 이해해야 멀티테넌시에 대해서 이야기 할 수 있다. 쉽게 말해 싱글테넌시는 위에서 말한바와 같이 사용자 혹은 고객별로 어플리케이션과 데이터베이스가 별개로 존재한다.

멀티네넌시는 하나의 어플리케이션에 여러 테넌트(사용자 혹은 고객)에게 서비스를 제공하면서 각 테넌트(고객 및 사용자) 별로 데이터와 설정을 격리한 상태로 관리하는 아키텍처 패턴이다. 주로 SaaS(Sofrware as at service ) 형태의 서비스에서 사용된다.

대표적인 서비스로 SaaS 형태의 CRM 서비스인 세일즈포스 닷컴이 있다.

멀티테넌시를 구성하기 위한 방법에 대해 살펴 보자.

데이터베이스별 테넌트 (database-per-Tenant)

Client 에서 서비스를 사용할때 단일 어플리 케이션을 사용하는 모습은 동일하며, 클라이언트는 각자의 DB 를 사용한다.

→ 데이터 분리 및 격리가 확실 하나, 확장 및 유지보수시 비용이 많이 발생될 수 있다.

스키마별 테넌트 (Schema-per-tenant)

데이터베이스별 테넌트와 비슷하며 , 공통 DB는 하나의 인스턴스를 가지고, 각 스키마는 테넌트 별로 분리 된다.

→ 단일 데이터베이스 내에서 관리함으로 비용 절감 효가가 있음 , 데이터 베이스 확장 성 및 유지수 시에 관련된 복잡도가 높아질수 있다.

  • 스키마 변경의 어려움
  • 버전관리
  • 테스트 및 배포
  • 확정성 제약
  • 보안 및 격리

위와 같은 부분에 있어, 하나의 DB 에서 관리 됨으로 변경시 고려해야할 제약사항 들이 많아진다.

보안과 격리 수준을 제외하고 데이터베이스별 테넌트와 단점이 유사하다.

테이블별 테넌트 (Row-level tenant)

단일 테이블 내에서 각 테넌트의 ID 를 사용하여 분리하는 방법으로 Application 을 개발하며 가장 많이 사용 하는 방법중에 하나이다.

데이터베이스 및 스키마에대한 별도의 제약없이 확장 가능 하지만, 통계와 같이 복잡한 쿼리 작성시 복잡도 가 증가 할 수있으며, 쿼리 성능이 저하될 수 있다.

참고

https://vladmihalcea.com/database-multitenancy/

멀티 데이터 소스 설정

Spring boot 기반 backend service 에서 멀티테넌시 아키텍처 구조를 적용하기 위해 Multi Datasource를 고려해 볼 수 있다.

Spring ver2 부터 멀티 데이터 소스에 대한 고민을 해결하기 위해 AbstractRoutingDataSource 를 제공하고 있다.

AbstractRoutingDataSource 의 일부를 보면 determineTargetDataSource() 에서 lookupKey 를 보고 어떤 datasource를 가져올지 결정한다.

이는 실제 @Repository 로 적용된 코드가 실행 되기 전에 실행되며 새로운 DataSource를 주입하게 된다.

/**
 * Retrieve the current target DataSource. Determines the
 * {@link #determineCurrentLookupKey() current lookup key}, performs
 * a lookup in the {@link #setTargetDataSources targetDataSources} map,
 * falls back to the specified
 * {@link #setDefaultTargetDataSource default target DataSource} if necessary.
 * @see #determineCurrentLookupKey()
 */
protected DataSource determineTargetDataSource() {
    Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");
    Object lookupKey = determineCurrentLookupKey();
    DataSource dataSource = this.resolvedDataSources.get(lookupKey);
    if (dataSource == null && (this.lenientFallback || lookupKey == null)) {
        dataSource = this.resolvedDefaultDataSource;
    }
    if (dataSource == null) {
        throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");
    }
    return dataSource;
}

간단한 그림으로 보면 다음과 같다.

 

 

repository 에서 persistence 의 method (save…update..)가 실행 되기 전에 Routing key를 요청 하고 필요한 datasource를 불러온다. 불온 온 datasource로 쿼리를 실행 한다.

client 에서 datasource를 획득하기 까지 AbstractRoutingDatasource 에서 좀더 상세하게 보면 다음과 같다.

Mybatis 에서 사용하는 “datasource router”

  • AbstractRoutingDatasource 에서 “Tenant Id“ 에 따른 데이터소스 생성 다이어그램

 

  • SqlSessionFactory
  • SqlSessionFactory는 데이터베이스(DataSource) 연결을 설정/관리하고 SqlSession 의 인스턴스를 생성하는 역할을 한다.
  • SqlSession
  • 데이터베이스와 실제 작업을 수행함
  • SqlSessionTemplate
  • Spring 프레임워크에서 제공하며, Spring의 트렌젝션 관리와 통합되어 Mybatis를 좀더 편리하게 사용 할 수있게 해준다. Spring의 트렌젝션 관리를 지원하고 예외 처리를 편리하게 해주는 등의 기능을 지원한다.

JPA 에서 사용하는 “datasource router”

  • AbstractRoutingDatasource 에서 “Tenant Id“ 에 따른 데이터소스 생성 다이어그램

  • EntityManagerFactoy
    • JPA 에서 데이터베이스와 연결을 설정 하고 EntityManager 를 생성하고 관리 한다.
    • 주로 애플리케이션 초기화 단계에서 생성된다.
  • EntityManager
    • JPA 에서 엔티티와 상호 작용하는 주요 인터페이스이다.
    • 엔티티를 데이터베이스에 CRUD 하는 작업을 수행한다.
    • 엔티티 메니저는 트랜잭션 범위내에서 동작되며 각 트랜잭션에 대해 새로운 EntityManager 인스턴스가 생성된다.

그림에서보면 AbstractRoutingDataSource 를 통해 이루어지는 멀티 테넌시 환경을 가정하고 있다. AbstractRoutingDataSource는 런타임시에 현제 테넌트에 해당되는 데이터베이스의 “DataSource” 를 선택하도록 해주는 라우팅 메커니즘을 제공한다. (위의 예제 코드 참고)

따라서 EntityManagerFactory는 여러데이터 소스를 관리하고 , 테넌트 아이디에 따라 EntityManager는 선택된 DataSource 를 통해 데이터 베이스와 상호작용한다.

JpaTransactionManager 를 추가하고 DB에 Connection 하는 상세 과정

  • (JPA)TransantionManager 를 통해 데이터를 롤백 하거나 커밋한다.
  • EntityManagerFactory 를 통해 생성된 EntityManager는 Connection pool 에서 관리되고 사용 한다.

멀티테넌시/멀티 테이터 소스 예제

조건

  • JPA 와 Mybatis DataSource 구성
  • Tenant Id 에따른 DataSource determine

Spring multi datasource, datasourceRouter

 
반응형