(DB) PlanetScale에서 Neon으로 이사가기

Apr 13, 2024

어느날, PlanetScale의 무료 플랜 종료 소식이 다가왔다.
얼른 이사가라고 수 통의 이메일을 받았다.

240408-171031

억장 와르르멘션이었다.
편리하게 사이드 프로젝트 데이터베이스를 무료 호스팅하고 있었는데 대안이 필요했다.

planetscale alternative free를 검색해보면 PostgreSQL은 supabase, neon SQLite은 turso, MySQL은 cockroach 등 선택지가 있다.

모두 매력적인 선택지이지만, Vercel Postgres에서 neon을 래핑해서 서빙하다는 소식, 또 요즘 핫한 PostgreSQL를 경험해보고 싶은 마음에 neon을 새둥지로 이사 가보기로 했다.

pgloader로 데이터 옮기기

pgloader는 PostgreSQL 데이터를 등록할 수 있는 오픈소스이다.
이를 활용해 MySQL 데이터를 PostgresSQL로 쉽게 옮길 수 있다.

MacOS 기준, brew로 쉽게 설치를 할 수 있으며,

brew install pgloader

아래 명령어로 MySQL에서 PostgreSQL로 데이터 마이그레이션 할 수 있다.

pgloader --with "quote identifiers" mysql://myuser@myhost/dbname pgsql://pguser@pghost/dbname

자세한 옵션명을 하나 하나 정리하면 아래와 같다.

--with "quote identifiers"

카멜 케이스를 그대로 유지시키는 명령어이다.
그게 아니면 테이블명도 그렇고 칼럼명도 그렇고 스네이크 케이스로 적용된다.

자세한 내용은 공식문서 참고하면 된다.

mysql://myuser@myhost/dbname

우선 PlanetScale CLI를 통해서 로컬 호스트로 DB를 접근할 수 있다.

pscale login
pscale connect mildvu --port 8080

따라서 MySQL 데이터베이스 호스트는 아래같이 입력하면 된다.

mysql://127.0.0.1:8080/mildvu"

pgsql://pguser@pghost/dbname

neon 대시보드에서 데이터베이스 connection string을 받아오면 된다.

240415-000917

마이그레이션 할 땐 Pooled connection 옵션을 적용하지 않아도 괜찮다.

추가적으로 endpoint 옵션을 넣어줘야 하는데 ep-xxx 부분을 잘 찾아서 입력해주면 된다.

postgresql://mildvu_owner:endpoint=ep-xxx;[password]@ep-xxx.ap-southeast-1.aws.neon.tech/main?sslmode=require

최종 형태 및 결과물

메모장에서 위 내용을 잘 조합하고, 이제 터미널에 명령어를 입력하면 된다.

pgloader --with "quote identifiers" mysql://127.0.0.1:8080/mildvu "postgresql://mildvu_owner:endpoint=ep-xxx;[password]@ep-xxx.ap-southeast-1.aws.neon.tech/main?sslmode=require"

그러면 아래 같은 리포트를 볼 수 있다.

240414-234023

크흠.. 나의 데이터는 사실 117.3KB 밖에 되지 않았다.. 작지만 소중해

240414-234137

neon의 Tables에도 데이터가 잘 이전된 것을 확인 할 수 있다 ✨

neon 스키마 이름 변경

현재 데이터는 기존 데이터베이스명인 “mildvu”로 neon의 스키마로 이관이 되었지만, prisma는 이름이 “public”인 스키마를 접근하게 되는 것 같다.

이래 저래 시도해봤지만 결국 스키마명을 수정하여 문제를 해결했다.

neon 대시보드에 있는 SQL Editor에서 아래 명령어로 스키마명을 변경할 수 있다.

ALTER SCHEMA "mildvu" RENAME TO "public"

prisma 설정

prisma에서 neon의 사용법은 공식문서 가이드 대로 진행하면 된다.

prisma env

neon 대시보드에 있는 Connection string을 가져오면 된다.
여기서는 Pooled connection을 활성화시키자.

.env
DATABASE_URL=postgresql://mildvu_owner:[password]@ep-ancient-firefly-a1fdd8wb-pooler.ap-southeast-1.aws.neon.tech/main?sslmode=require

prisma schema

MySQL 대신 PostgreSQL을 명시하면 된다.

prisma/schema.prisma
generator client {
  provider        = "prisma-client-js"
-  previewFeatures = ["referentialIntegrity"]
+  previewFeatures = ["driverAdapters"]
}
 
datasource db {
-  provider     = "mysql"
+  provider     = "postgresql"
  url          = env("DATABASE_URL")
-  referentialIntegrity = "prisma"
+  relationMode = "prisma"
}

생각보다 큰 충돌은 없었다.

추가적으로 문자열 관련 어노테이션을 수정해주면 되었다.
@db.MediumText, @db.LongText@db.VarChar()

prisma client

변경된 스키마 바탕으로 prisma client을 생성하고,

npx prisma generate

가이드 대로 코드를 수정하면 된다.

import { neonConfig, Pool } from '@neondatabase/serverless';
import { PrismaNeon } from '@prisma/adapter-neon';
import { PrismaClient } from '@prisma/client';
import ws from 'ws';
 
declare global {
  var _prisma: PrismaClient | undefined;
}
 
neonConfig.webSocketConstructor = ws;
const connectionString = `${process.env.DATABASE_URL}`;
 
const pool = new Pool({ connectionString });
const adapter = new PrismaNeon(pool);
const _prisma = global._prisma || new PrismaClient({ adapter });
 
if (process.env.NODE_ENV === 'development') {
  global._prisma = _prisma;
}
 
export default _prisma;

npx prisma generate을 하지 않으면 타입 에러, 런타임 에러가 발생하니 꼭 유의하도록 하자.

맺으면서

사이드 프로젝트를 유지보수하는 것이 쉽지가 않는 것 같다.
특히 인프라 이슈가 있을 땐 진짜 맨땅에 헤딩이다.

하지만 덕분에 더 다양한 serverless 플랫폼을 알게 되었고, DB와도 조금 더 친해졌다.
앞으로 더 친해져 봐요 우리…

한편으로 Vercel이 무료 플랜을 종료한다면 어떻하지 머리가 아찔해졌다.