catsridingCATSRIDING|OCEANWAVES
Developer Tools

Amazon RDS for MySQL 데이터를 Supabase 데이터베이스로 이전하기

jynn@catsriding.com
Dec 09, 2024
Published byJynn
999
Amazon RDS for MySQL 데이터를 Supabase 데이터베이스로 이전하기

Migrating Amazon RDS For MySQL Database to Supabase

AWS RDS의 프리티어 기간이 종료되면서 추가적인 비용이 발생하게 되었습니다. 현재 블로그 서비스는 큰 규모가 아니기 때문에, 무료로 제공되는 Supabase로 데이터를 이전하는 것이 적합하다고 판단했습니다. Supabase는 PostgreSQL을 기반으로 일정 수준까지 무료로 제공되며, 실시간 API, 인증, 스토리지와 같은 다양한 기능을 지원합니다.

이 글에서는 Google Colab을 활용해 Amazon RDS for MySQL에서 Supabase로 데이터를 이전한 경험을 정리하였습니다. 아래 내용을 따라하면 Google Colab을 이용해 데이터를 간단히 이전할 수 있습니다.

Prerequisites

이전 작업에 필요한 Amazon RDS for MySQL 데이터베이스와 Supabase PostgreSQL의 커넥션 정보를 준비합니다.

기존에 운영 중인 MySQL 데이터베이스의 커넥션 정보는 보통 별도로 관리되고 있겠지만, 만약 접속 정보가 없다면 AWS 콘솔에서 확인할 수 있습니다. Connectivity & Security 탭에서 데이터베이스의 Endpoint와 Port를 확인하고, Configuration 탭에서 데이터베이스 이름과 사용자 이름을 확인하세요. 비밀번호를 알 수 없을 경우 새로 생성하여 기록해 두면 됩니다.

migrating-amazon-rds-for-mysql-database-to-supabase_00.png

그리고 Supabase에 접속하여 계정을 생성하고 프로젝트를 만든 뒤, PostgreSQL 커넥션 정보를 확인합니다. Database Settings 탭에서 Connection string의 PostgreSQL URI와 비밀번호를 복사합니다. 이 정보는 데이터 이전 작업에서 사용됩니다.

migrating-amazon-rds-for-mysql-database-to-supabase_01.png

각 데이터베이스 커넥션 정보가 준비되었다면, 이제 Google Colab을 활용하여 데이터 이전 작업을 진행합니다.

Migration Using Google Colab

Google Colab은 손쉽게 데이터 마이그레이션 작업을 수행할 수 있는 클라우드 기반 Python 환경입니다. Supabase는 Google Colab에서 실행할 수 있는 마이그레이션 툴을 제공하여 데이터를 빠르게 이전할 수 있도록 지원합니다.

1. MySQL 엔진 설치하기

Supabase Migration Tool에 접속하면 세 가지 주요 단계로 나뉩니다. 첫 번째 단계는 데이터베이스 엔진을 설치하는 것입니다.

Colab 노트북의 첫 번째 셀에서 데이터베이스 엔진을 선택하고 실행하면 MySQL용 엔진인 pgloader와 관련 패키지가 설치됩니다. 이는 네트워크 속도에 따라 다르지만 보통 몇 분 정도 소요됩니다.

migrating-amazon-rds-for-mysql-database-to-supabase_02.png

아래는 설치가 완료된 후 출력되는 로그의 예시 입니다:

--2024-12-09 06:03:11--  https://raw.githubusercontent.com/mansueli/Supa-Migrate/main/after.sql
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.108.133, 185.199.109.133, 185.199.110.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.108.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 54 [text/plain]
Saving to: ‘after.sql’

after.sql           100%[===================>]      54  --.-KB/s    in 0s      

2024-12-09 06:03:11 (632 KB/s) - ‘after.sql’ saved [54/54]

--2024-12-09 06:03:11--  https://raw.githubusercontent.com/mansueli/Supa-Migrate/main/before.sql
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.108.133, 185.199.109.133, 185.199.110.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.108.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 49 [text/plain]
Saving to: ‘before.sql’

before.sql          100%[===================>]      49  --.-KB/s    in 0s      

2024-12-09 06:03:12 (3.55 MB/s) - ‘before.sql’ saved [49/49]

./pgloader/pgloader-3.6.9/build/bin/pgloader [ option ... ] command-file ...
./pgloader/pgloader-3.6.9/build/bin/pgloader [ option ... ] SOURCE TARGET
  --help -h                       boolean  Show usage and exit.
  --version -V                    boolean  Displays pgloader version and exit.
  --quiet -q                      boolean  Be quiet
  --verbose -v                    boolean  Be verbose
  --debug -d                      boolean  Display debug level information.
  --client-min-messages           string   Filter logs seen at the console (default: "warning")
  --log-min-messages              string   Filter logs seen in the logfile (default: "notice")
  --summary -S                    string   Filename where to copy the summary
  --root-dir -D                   string   Output root directory. (default: #P"/tmp/pgloader/")
  --upgrade-config -U             boolean  Output the command(s) corresponding to .conf file for
                                           v2.x
  --list-encodings -E             boolean  List pgloader known encodings and exit.
  --logfile -L                    string   Filename where to send the logs.
  --load-lisp-file -l             string   Read user code from files
  --dry-run                       boolean  Only check database connections, don't load anything.
  --on-error-stop                 boolean  Refrain from handling errors properly.
  --no-ssl-cert-verification      boolean  Instruct OpenSSL to bypass verifying certificates.
  --context -C                    string   Command Context Variables
  --with                          string   Load options
  --set                           string   PostgreSQL options
  --field                         string   Source file fields specification
  --cast                          string   Specific cast rules
  --type                          string   Force input source type
  --encoding                      string   Source expected encoding
  --before                        string   SQL script to run before loading the data
  --after                         string   SQL script to run after loading the data
  --self-upgrade                  string   Path to pgloader newer sources
  --regress                       boolean  Drive regression testing
Pgloader installed to migrate MySQL to Supabase

2. 데이터베이스 커넥션 정보 세팅하기

MySQL 엔진 설치가 완료되면, 다음 단계는 AWS RDS와 Supabase의 접속 정보를 환경변수로 설정하는 것입니다. 아래 코드를 참고하여 각 변수에 적절한 값을 입력합니다.

#Source DB variables:
%env HOST=my-aurora-cluster-instance.c1xy5example.123456789012.eu-central-1.rds.amazonaws.com
%env USER=mysql_u1
%env SOURCE_DB=mysequel
%env PASSWORD=pass123
%env PORT=3306
#Supabase variables:
%env SUPAVISOR_URL=postgres://postgres.project:[YOUR-PASSWORD]@aws-0-us-west-1.pooler.supabase.com:5432/postgres
%env SUPABASE_PASSWORD=mypassword

변수는 다음과 같습니다:

  • Source Database
    • HOST: MySQL 데이터베이스의 호스트 주소
    • USER: MySQL 사용자 이름
    • SOURCE_DB: MySQL 데이터베이스 이름
    • PASSWORD: MySQL 사용자 비밀번호
    • PORT: MySQL 포트
  • Target Database
    • SUPAVISOR_URL: Supabase PostgreSQL 연결 URI
      • Supabase 대시보드에서 제공된 연결 정보를 사용하며, [YOUR-PASSWORD]는 그대로 입력합니다. 이 값은 이후 SUPABASE_PASSWORD 환경변수로 자동으로 대체됩니다.
    • SUPABASE_PASSWORD: Supabase PostgreSQL 비밀번호

위의 환경변수를 입력한 후 해당 셀을 실행하여 설정을 완료합니다.

migrating-amazon-rds-for-mysql-database-to-supabase_03.png

3. 마이그레이션 실행하기

환경변수가 설정되면 다음 단계는 데이터를 실제로 마이그레이션하는 것입니다. Running the Migration 셀을 실행합니다.

migrating-amazon-rds-for-mysql-database-to-supabase_04.png

마이그레이션 작업이 완료되면 다음과 같은 리포트가 출력됩니다:

2024-01-23T18:09:15.037003Z LOG pgloader version "3.6.7~devel"
2024-01-23T18:09:16.080102Z LOG Migrating from #<MYSQL-CONNECTION mysql://u958315775_UdUM6@srv818.hstgr.io:3306/u958315775_kMPKj {10070A9A43}>
2024-01-23T18:09:16.083102Z LOG Migrating into #<PGSQL-CONNECTION pgsql://postgres.gvvgnpzflrktbmpvrkwt@aws-0-us-west-1.pooler.supabase.com:5432/postgres {1007564593}>
2024-01-23T18:09:46.631985Z LOG report summary reset
                                 table name     errors       rows      bytes      total time
-------------------------------------------  ---------  ---------  ---------  --------------
                                before load          0          3                     0.611s
                            fetch meta data          0        132                     1.855s
                             Create Schemas          0          0                     0.037s
                           Create SQL Types          0          2                     0.534s
                              Create tables          0         58                     6.627s
                             Set Table OIDs          0         29                     0.047s
-------------------------------------------  ---------  ---------  ---------  --------------
                u958315775_kmpkj.wp_options          0        788     1.2 MB          2.237s
               u958315775_kmpkj.wp_postmeta          0        188    27.8 kB          1.230s
                  u958315775_kmpkj.wp_posts          0        103   187.6 kB          1.635s
        u958315775_kmpkj.wp_redirection_404          0        109    20.5 kB          1.345s
     u958315775_kmpkj.wp_litespeed_url_file          0         91     4.8 kB          1.079s
  u958315775_kmpkj.wp_litespeed_img_optming          0         48     2.0 kB          1.118s
     u958315775_kmpkj.wp_litespeed_img_optm          0         45     2.3 kB          1.030s
               u958315775_kmpkj.wp_usermeta          0         29     3.5 kB          1.029s
       u958315775_kmpkj.wp_redirection_logs          0         21     4.8 kB          1.021s
   u958315775_kmpkj.wp_actionscheduler_logs          0         18     1.2 kB          0.952s
       u958315775_kmpkj.wp_litespeed_avatar          0         15     1.9 kB          1.027s
     u958315775_kmpkj.wp_term_relationships          0         12     0.1 kB          0.956s
u958315775_kmpkj.wp_actionscheduler_actions          0         10     3.3 kB          0.992s
           u958315775_kmpkj.wp_aioseo_cache          0          8    79.4 kB          1.397s
          u958315775_kmpkj.wp_litespeed_url          0         14     0.3 kB          0.964s
                  u958315775_kmpkj.wp_terms          0          8     0.2 kB          0.978s
          u958315775_kmpkj.wp_term_taxonomy          0          8     0.2 kB          0.987s
               u958315775_kmpkj.wp_comments          0          1     0.3 kB          0.998s
     u958315775_kmpkj.wp_wpforms_tasks_meta          0          3     0.2 kB          0.954s
 u958315775_kmpkj.wp_actionscheduler_groups          0          3     0.0 kB          0.988s
           u958315775_kmpkj.wp_aioseo_posts          0          2     0.9 kB          0.983s
     u958315775_kmpkj.wp_redirection_groups          0          2     0.1 kB          0.981s
                  u958315775_kmpkj.wp_users          0          1     0.1 kB          0.979s
 u958315775_kmpkj.wp_actionscheduler_claims          0          0                     0.974s
   u958315775_kmpkj.wp_aioseo_notifications          0          0                     0.956s
            u958315775_kmpkj.wp_commentmeta          0          0                     0.987s
                  u958315775_kmpkj.wp_links          0          0                     0.981s
      u958315775_kmpkj.wp_redirection_items          0          1     0.1 kB          0.944s
               u958315775_kmpkj.wp_termmeta          0          0                     1.010s
-------------------------------------------  ---------  ---------  ---------  --------------
                    COPY Threads Completion          0          4                    14.394s
                             Create Indexes          0        103                    12.073s
                     Index Build Completion          0        103                     0.714s
                            Reset Sequences          0         28                     0.505s
                               Primary Keys          0         29                     3.250s
                        Create Foreign Keys          0          0                     0.000s
                            Create Triggers          0          0                     0.074s
                            Set Search Path          0          1                     0.184s
                           Install Comments          0          5                     0.555s
                                 after load          0          3                     0.739s
-------------------------------------------  ---------  ---------  ---------  --------------
                          Total import time1528     1.5 MB         32.489s
Migration completed

마이그레이션 중 MySQL과 PostgreSQL 데이터 타입 불일치 또는 다른 이유로 인해 오류가 발생할 수 있습니다. 이 경우 pgloader의 옵션을 수정하거나 스키마를 사전에 조정해야 할 수 있습니다.

4. 데이터 이전 확인하기

마이그레이션 작업이 완료되면 Supabase Dashboard로 이동하여 데이터가 정상적으로 이전되었는지 확인합니다. Supabase의 PostgreSQL 스키마는 MySQL과 구조적으로 다를 수 있지만, pgloader가 자동으로 스키마를 생성해줍니다. 필요한 경우 수동으로 조정할 수도 있습니다.

migrating-amazon-rds-for-mysql-database-to-supabase_05.png

Wrapping It Up

Google Colab의 Supabase Migration Tool을 활용하여 Amazon RDS for MySQL에서 데이터를 손쉽게 Supabase로 이전할 수 있었습니다. Google Colab 환경에서 작업이 진행되었지만, 실제 데이터 이전에는 MySQL 데이터를 PostgreSQL로 마이그레이션하는 데 널리 사용되는 오픈소스 도구인 pgloader가 사용되었습니다. 참고로, pgloader는 로컬 머신에 설치해 직접 실행하는 방법도 제공하므로, 상황에 따라 다양한 방식으로 활용할 수 있습니다.

현재 API 서버는 Spring Data JPA를 중심으로 동작하고 있어, 일부 엔티티 매핑 과정에서 데이터 타입을 조정해야 하는 경우가 있었지만, 전반적으로 큰 수정 없이 마이그레이션을 원활히 완료할 수 있었습니다.


  • Database