멀티-테넌시란?
멀티-테넌시는 소프트웨어 어플리케이션의 단일 이느턴스가 여러 고객에게 서비스를 제공하는 아키텍처 이다.
아래 그림에서 보듯이 싱클 테넌시와 멀티테넌시는 확실하게 구분된다.
싱글테넌시의 경우 사용자 별로 어플리케이션과 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
'소프트웨어공학 > Architecture' 카테고리의 다른 글
tenant id 에 따른 datasource 분리 , 인터셉터 (0) | 2025.01.09 |
---|