고트래픽 Rails 앱의 PostgreSQL에서 PlanetScale MySQL로의 무중단 라이브 마이그레이션

Migrating Whop from PostgreSQL to PlanetScale MySQL with 0 downtime

작성자
발행일
2025년 10월 28일

핵심 요약

  • 1 Whop의 고트래픽 Rails 애플리케이션을 PostgreSQL에서 PlanetScale MySQL로 무중단 마이그레이션한 전략을 다룹니다.
  • 2 듀얼 데이터베이스 모드를 활용하여 개발팀의 기능 출시를 지속하면서 데이터베이스 호환성 문제를 병렬로 해결했습니다.
  • 3 PostgreSQL과 MySQL 간의 데이터 타입, 인덱스, 쿼리 구문 등 미묘한 차이를 극복한 실질적인 해결책을 제시합니다.

도입

Whop은 트래픽 급증으로 인해 기존 PostgreSQL 데이터베이스가 한계에 도달하자, PlanetScale MySQL로의 데이터베이스 마이그레이션을 결정했습니다. Evil Martians는 개발 중단이나 서비스 다운타임 없이 이 고트래픽 Rails 애플리케이션을 성공적으로 이전하는 과제를 맡았습니다. 이 과정에서 두 데이터베이스 간의 미묘하지만 중요한 차이점을 극복하며, 개발팀의 기능 출시 속도를 유지하는 혁신적인 전략을 적용했습니다. 본 문서는 이러한 복잡한 마이그레이션의 기술적 도전과 해결책을 상세히 다룹니다.

듀얼 데이터베이스 전략으로 개발 속도 유지

개발 중단 없는 마이그레이션을 위해 Rails 앱을 듀얼 데이터베이스 모드로 운영했습니다. on_mysql? 헬퍼 메서드를 통해 PostgreSQL과 MySQL 간 전환이 가능하게 하여, 개발팀은 기존 DB에서 기능 개발을, 마이그레이션 팀은 MySQL 호환성을 병렬로 확보했습니다. 이는 database.yml 설정의 동적 변경 및 LIKE/ILIKE와 같은 DB별 쿼리 구문 차이를 조건문으로 처리하는 방식으로 구현되었습니다.

스키마 및 데이터 타입 마이그레이션 과제

  • 정밀도 문제: MySQL은 DECIMAL 및 타임스탬프에 명시적인 정밀도와 스케일 지정이 필수적입니다.

  • JSON 및 배열: PostgreSQL JSONB는 MySQL JSON으로 이전되나, JSON 함수 직접 인덱싱 제한으로 GENERATED ALWAYS AS 컬럼을 활용했습니다. 네이티브 배열은 JSON 직렬화가 필요하며, PostgreSQL STORED 생성 컬럼 사용 시 대규모 테이블 재작성 이슈에 유의해야 합니다.

  • 부분 인덱스: MySQL에는 이 기능이 없어, NULL의 고유 특성을 활용한 조건부 NULL 값 생성으로 고유 제약을 구현했습니다.

쿼리 구문 및 정렬 방식의 차이

  • NULL 정렬: 두 DB의 NULL 기본 정렬 순서가 다르며, MySQL은 NULLS FIRST/LAST 구문을 지원하지 않습니다. Arel 사용 또는 조건부 정렬로 이식성을 확보했습니다.

  • DISTINCT ON: PostgreSQL 전용 기능으로, MySQL에서는 서브쿼리 및 윈도우 함수로 대체했습니다.

결론

이번 마이그레이션은 단순한 데이터베이스 교체를 넘어, 애플리케이션 아키텍처를 대상 데이터베이스의 철학에 맞춰 재구성하는 과정이었습니다. PostgreSQL의 편리한 기능들을 MySQL의 강점에 맞게 변환하는 작업은 필수적이었으며, 듀얼 데이터베이스 패턴은 개발 중단 없이 마이그레이션을 성공시키는 데 결정적인 역할을 했습니다. 마이그레이션 전 JSONB 컬럼, 배열 필드, 부분 인덱스, DECIMAL 정밀도, NULL 정렬 의존성 등에 대한 철저한 사전 감사가 중요하며, 대상 데이터베이스의 관점을 포용하는 것이 성공의 핵심임을 시사합니다.

댓글 0

로그인이 필요합니다

댓글을 작성하거나 대화에 참여하려면 로그인이 필요합니다.

로그인 하러 가기

아직 댓글이 없습니다

첫 번째 댓글을 작성해보세요!