본문으로 건너뛰기

Prisma로 멀티 스키마 지정, 멀티 데이터베이스 연결 방법

 · reading-time-plural · 

Prisma 으로 멀티 테넌트(Multi-tenant) 구조를 위한 멀티 스키마(Multiple schemas) , 멀티 데이터베이스 연결(Multi-database connection) 방법을 소개합니다.

개요

프로젝트 진행 중 SaaSDB 설계를 위해서 멀티 테넌트(Multi-tenant) 구조가 필요하여 멀티 데이터베이스 연결(Multi-database connection) 과 함께 멀티 스키마(Multiple schemas) 지원이 필요하였습니다.

여기서 멀티 테넌트(Multi-tenant) 란?

하나의 애플리케이션 또는 소프트웨어 인스턴스 가 여러 사용자 또는 테넌트(tenant) 를 지원하는 아키텍처를 지칭합니다.

이 용어는 주로 클라우드 컴퓨팅 , SaaS(Software as a Service) 모델 또는 대규모 엔터프라이즈 애플리케이션 에서 사용되며, 여러 고객이나 사용자 그룹이 동일한 애플리케이션 인스턴스를 공유하되, 각각의 데이터와 구성이 격리되어 있는 환경을 의미합니다.

아래의 요구 사항을 충족할 수 있어야 했습니다.

  • 커넥션동적 으로 변경할 수 있어야 합니다.
  • 커넥션 과 관계없이 원하는 스키마를 지정 해서 쿼리 할 수 있어야 합니다.

프로젝트에서 Prisma 를 사용하고 있었는데 Prisma 은 선언적으로 정의된 Schema 를 기준으로 Client 가 생성되기 때문에 여러 개의 SchemaConnection 을 가질 수 있는지 의문이었고 이에 대해 찾아보게 되었습니다.

멀티 지정 방법을 지원하는가?

찾아보니 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 가 한 개만 존재할 수 있는 것처럼 생겨서 헷갈릴 수 있는데 현재는 스키마 에 맞게 Clientgenerator 하므로 아래의 방법으로 필요한 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 Clientgenerator 되지 않고 이상하게 파일이 생성됩니다.

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문이 생성됩니다. 이전에 생성된 migratetabledrop 하는 코드가 들어가 있습니다. 오른쪽 sql 은 왼쪽 sql 보다 늦게 migrate 으로 생성된 sql 인데 DROP TABLE "User"; 이라는 의도하지 않는 쿼리가 있는 것을 확인할 수 있습니다. 이는 이전 migratediff 하여 생성되었기 때문입니다.

  • 큰 문제는 아닌데 스키마 파일이 바뀌기 때문에 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 가 걱정되는 부분이 있습니다.

읽어주셔서 감사합니다.