Prisma
으로 멀티 테넌트(Multi-tenant)
구조를 위한 멀티 스키마(Multiple schemas)
, 멀티 데이터베이스 연결(Multi-database connection)
방법을 소개합니다.
개요
프로젝트 진행 중 SaaS
형 DB
설계를 위해서 멀티 테넌트(Multi-tenant)
구조가 필요하여 멀티 데이터베이스 연결(Multi-database connection)
과 함께 멀티 스키마(Multiple schemas)
지원이 필요하였습니다.
여기서 멀티 테넌트(Multi-tenant) 란?
하나의 애플리케이션
또는 소프트웨어 인스턴스
가 여러 사용자 또는 테넌트(tenant)
를 지원하는 아키텍처를 지칭합니다.
이 용어는 주로 클라우드 컴퓨팅
, SaaS(Software as a Service)
모델 또는 대규모 엔터프라이즈 애플리케이션
에서 사용되며, 여러 고객이나 사용자 그룹이 동일한 애플리케이션 인스턴스를 공유하되, 각각의 데이터와 구성이 격리되어 있는 환경을 의미합니다.
아래의 요구 사항을 충족할 수 있어야 했습니다.
커넥션
을동적
으로 변경할 수 있어야 합니다.커넥션
과 관계없이원하는 스키마를 지정
해서쿼리
할 수 있어야 합니다.
프로젝트에서 Prisma
를 사용하고 있었는데 Prisma
은 선언적으로 정의된 Schema
를 기준으로 Client
가 생성되기 때문에 여러 개의 Schema
와 Connection
을 가질 수 있는지 의문이었고 이에 대해 찾아보게 되었습니다.
멀티 지정 방법을 지원하는가?
찾아보니 3가지 선택지가 있더군요.
Third Party: prisma-multi-tenant
https://github.com/errorname/prisma-multi-tenant 를 찾을 수 있었는데 여러 개의 커넥션
을 가질 수 있긴 한데 스키마
가 고정
되어야 한다고 합니다.
즉, 같은 스키마인데 DB가 여러 개인 경우 사용될 수 있을 것인데 제 요구 상황과 다름으로 배제하였습니다.
Prisma 공식 지원
Prisma with multiple database schemas 라는 이름으로 Prisma
공식 문서에 있더군요.
테스트는 해보지 않았지만 Prisma
에서 멀티 스키마
를 지원하려고 하는 거 같습니다.
근데 문서를 보면 동적으로 커넥션 정보를 바꾸고 싶은데 그런 것이 가능할지 의문이었습니다.
여러 개의 Schema를 정의하고 Client generator 하기
Prisma multiple connections
라고 구글링
하여 https://github.com/prisma/prisma/issues/2443#issuecomment-630679118 방법을 찾을 수 있었습니다.
여러 개의 Schema
를 정의하고 Client generator
하는 방법이었는데 Prisma
의 기본 메커니즘을 따라 하는 것이며 동작 방식이 명확해서 이것을 사용하기로 하였습니다.
멀티 지정 방법
info
구현체는 코드는 parkgang/prisma-multi-schemas-and-multi-connections 에 존재합니다.
README
에 지정 방법을 작성했으니 해당 방법을 보는 것이 도움이 되실 것입니다. 해당 글에서는 핵심
과 주의점
에 대해서 서술하겠습니다.
multiple schemas
시나리오이기 때문에*.prisma
는 여러 개 생성되어야 합니다.*.prisma
단위로 스키마가 정의됩니다.- 스키마가 헷갈리면
DB 단위
라고 생각하세요. - 스키마에는
여러 Table
이 정의될 것입니다.
스키마
에 맞는Client
를 호출해야 하는데 공식 문서에는import { PrismaClient } from '@prisma/client'
으로Client
가 한 개만 존재할 수 있는 것처럼 생겨서 헷갈릴 수 있는데 현재는스키마
에 맞게Client
를generator
하므로 아래의 방법으로 필요한Client
를 호출할 수 있습니다.import { PrismaClient as PrismaClientCatalog } from "./prisma/catalog/client";
import { PrismaClient as PrismaClientTenant } from "./prisma/tenant/client";스키마
에 맞는커넥션
을동적
으로 변경할 수 있어야 하는데 아래의 문법으로 변경할 수 있습니다.import { PrismaClient } from "@prisma/client";
const client1 = new PrismaClient({
datasources: { db: { url: "postgres://localhost/db1" } },
});
const client2 = new PrismaClient({
datasources: { db: { url: "postgres://localhost/db2" } },
});
이렇게 스키마
에 맞는 Client
를 호출해서 원하는 커넥션
을 물려서 사용할 수 있는 환경이 마련되었습니다.
Insight
npm i @prisma/client
가 설치된 상태에서 진행해야 한다
스키마
에 맞게 Prisma Client generator
을 하니까 굳이 @prisma/client
패키지가 필요한가? 싶을 수 있습니다.
설치하지 않으면 아래와 같은 에러 메시지와 함께 Prisma Client
가 generator
되지 않고 이상하게 파일이 생성됩니다.
Error: Could not resolve @prisma/client despite the installation that we just tried.
Please try to install it by hand with npm install @prisma/client and rerun prisma generate 🙏.
해당 이유는 공식문서 https://www.prisma.io/docs/getting-started/setup-prisma/start-from-scratch/relational-databases/install-prisma-client-typescript-sqlserver 를 보니까 아래의 다이어그램
으로 잘 설명되어 있습니다.
스키마
는 독립적인 디렉터리에서 관리하는 것이 좋다
아래와 같이 하나의 디렉터리에서 관리하면 좋지 않다는 것을 의미합니다.
이유는 아래와 같은데
migrate
시 구분이 어렵습니다. 2개의 스키마에 대해서 동시에 진행되기 때문인데 만약,db1
,db2
의 스키마 모두init
이라고 이름을 지정하면 어떻게 구분할 건가요? 시간 차이로 인하여 아래와 같이 생길 텐데 구분이 어렵습니다. 물론00000000000000_db1_init
,00000000000000_db2_init
와 같이 구분하여 이름을 지정할 수 있겠지만 이건 원초적인 해결 방법이 아닙니다.db1
,db2
모두init
라고 하니까 구분이 어렵습니다.원초적으로
migrate
시 이전 스키마와 비교하여 sql문이 생성되는데 이전 스키마가 같은 스키마를 기준으로 하지 않기 때문에 아래와 같이 이상한 sql문이 생성됩니다. 이전에 생성된migrate
의table
을drop
하는 코드가 들어가 있습니다. 오른쪽sql
은 왼쪽sql
보다 늦게migrate
으로 생성된sql
인데DROP TABLE "User";
이라는 의도하지 않는 쿼리가 있는 것을 확인할 수 있습니다. 이는 이전migrate
와diff
하여 생성되었기 때문입니다.큰 문제는 아닌데 스키마 파일이 바뀌기 때문에
CLI
에서 파일 이름을 지정해야 하는 귀찮음이 있습니다.npx prisma migrate dev --name init --schema prisma/db1-schema.prisma
npx prisma migrate dev --name init --schema prisma/db2-schema.prisma
고로 아래와 같이 독립적인 디렉터리에서 관리해야지 스키마 파일 이름도 깔끔하게 schema.prisma
으로 떨어져서 기본 값으로 지정되어 찾기가 편하고 migrate
시 차곡차곡 지정됩니다.
마무리
이렇게 Prisma
에서 멀티 스키마(Multiple schemas)
, 멀티 데이터베이스 연결(Multi-database connection)
방법에 대해서 알아보았습니다.
Prisma
Hello, world
에서는 DB 연결
을 위해 따로 지정 없이 종속된 Schema
정보를 이용하길래 멀티 연결
이 가능한가 걱정이 있었는데 이해하고 해보니까 생각보다 손쉽게 구현할 수 있었습니다.
아쉬운 점으로 Prisma
에서 공식으로 지원하는 것이 아닌 Client generator
방법을 응용한 것이라 업데이트
에 따른 Breaking Changes
가 걱정되는 부분이 있습니다.
읽어주셔서 감사합니다.