멀티 테넌트
멀티 테넌트 아키텍처는 하나의 애플리케이션 인프라에서 여러 개의 고객(테넌트)이 서비스를 공유하도록 하는 시스템을 의미합니다.
각 테넌트는 동일한 애플리케이션과 데이터베이스 인프라를 사용하지만, 데이터와 사용자 경험은 서로 독립적이어서 다른 테넌트와는 철저히 분리됩니다.
멀티 테넌트 환경에서 데이터베이스를 관리하는 여러 방식 중, 하나의 데이터베이스에 여러 스키마를 사용하는 방법을 살펴보겠습니다.
데이터베이스 구조
이 예제에서는 test1, test2 등의 구조를 사용하며, 각 테넌트는 하나의 스키마와 연관되어 있습니다.
사용자가 데이터를 조회할 때, 해당 사용자가 속한 테넌트(스키마)를 파악한 후, 해당 스키마에서 데이터를 조회하게 됩니다.
MyBatis에서는 스키마명을 파라미터로 직접 전달하여 다음과 같이 구현할 수 있습니다.
SELECT *
FROM ${database}.multi_entity
JPA에서의 동적 스키마 변경
JPA에서 동적으로 스키마 명을 변경하기 위해 StatementInspector를 사용합니다.
StatementInspector는 Hibernate에서 SQL 쿼리를 실행하기 전에 이를 가로채서 필요한 처리를 할 수 있습니다.
Entity 생성
// Constants.kt
const val SCHEMA_NAME_PLACEHOLDER = "@@schema_name@@"
// MultiEntity.kt
@Entity
@Table(name = "multi_entity", catalog = SCHEMA_NAME_PLACEHOLDER)
class MultiEntity(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Int,
val name: String
)
스키마명에 구분 가능한 특정 문자를 넣어줍니다.
CustomStatementInspector
/**
* StatementInspector를 상속받아서 inspect 메소드를 오버라이드하여
* SCHEMA_NAME_PLACEHOLDER를 실제 스키마 이름으로 변경하는 클래스
*/
class CustomStatementInspector : StatementInspector {
override fun inspect(sql: String?): String {
return sql!!.replace(SCHEMA_NAME_PLACEHOLDER, DBUtils.getSchemaName())
}
}
StatementInspector의 inspect 메소드를 오버라이드합니다.
파라미터로 넘어온 sql에서 @@schema_name@@을 지정된 스키마명으로 치환해줍니다.
HibernateConfig
@Configuration
class HibernateConfig {
@Bean
fun hibernatePropertiesCustomizer(): HibernatePropertiesCustomizer {
return HibernatePropertiesCustomizer { properties: MutableMap<String?, Any?> ->
properties[AvailableSettings.STATEMENT_INSPECTOR] = CustomStatementInspector()
}
}
}
CustomStatementInspector를 등록해줍니다
결과
@Test
fun test() {
// test1 스키마에 있는 데이터
DBUtils.setSchemaName("test1")
val test1Result = multiEntityRepository.findById(1).get()
assert(test1Result.name == "test1 스키마")
// test2 스키마에 있는 데이터
DBUtils.setSchemaName("test2")
val test2Result = multiEntityRepository.findById(1).get()
assert(test2Result.name == "test2 스키마")
// default 스키마에 있는 데이터
val singleSchemaResult = singleEntityRepository.findById(1).get()
assert(singleSchemaResult.name == "test1 스키마")
}
같은 Repository를 이용해 조회하지만, 동적으로 스키마명이 바뀌는 것을 볼 수 있습니다.
예제 Github 주소
'Programming > SpringBoot' 카테고리의 다른 글
Spring Boot 동시성 제어 (1) - synchronized (0) | 2025.04.08 |
---|---|
[SpringBoot] AMQP란? (0) | 2025.01.26 |
[SpringBoot] @ModelAttribute 작동 원리 (0) | 2024.07.17 |
[SpringBoot] Entity의 ID를 테스트에서 삽입하는 방법 (0) | 2024.06.02 |
[SpringBoot] @ResponseBody 원리 (0) | 2024.01.29 |