pile·
DB / 데이터·매스프레소(콴다)매스프레소(콴다)·

Aurora/RDS 전문가의 GCP Cloud SQL이전기

콴다팀이 AWS Aurora/RDS for MySQL과 DynamoDB를 GCP Cloud SQL for MySQL로 이관하며 겪은 검토, 준비, 실행 과정을 정리한 글이다. service downtime 10분 이내와 이전 비용 최소화를 목표로, 유료 마이그레이션 솔루션(DMS, Datastream) 없이 mysqldump와 netcat, binlog 복제로 진행했다.

핵심 포인트
  • 목표는 DB 이전, DEV 환경을 {1 DB:n App}에서 {1 DB:1 App}로 전환, query/schema/index 최적화, MySQL 버전 업그레이드 4가지이며 모두 다운타임과 비용 최소화가 전제였다.
  • 이전 전에 grafana + VictoriaMetrics + mysql/rds exporter로 모니터링을 세우고 general.log와 pt-query-digest로 실행 쿼리를 분석했다.
  • single index 남발, 불필요한 OR, transaction 남용, 과도한 longtext/varchar 등 부하 요인을 찾아 복합 인덱스와 default 값, 타입 축소로 개선했다.
  • Aurora 5.7과 Cloud SQL 8.0의 옵티마이저/parameter 차이를 검토했고, DynamoDB는 data copy 애플리케이션으로 이전해 비용을 약 1/8로 절감했다.
  • binlog 복제(failover) 방식으로 이전하며 innodb_flush_log_at_trx_commit과 replica_type_conversions 설정으로 복제 오류를 방지했다.
  • GCP는 source writer 직접 복제가 불가해 External meta virtual instance를 만들어 API로 demote와 복제를 구성했다.
상세 정리
  • 사전 검토 5단계: 실행 쿼리(general.log + pt-query-digest), schema/parameter, replica 구축 시간, 버전 차이, DB 종류 단일화를 순서대로 점검했다.
  • 쿼리 문제: SELECT 1 같은 저부하 쿼리도 양이 많으면 부하가 되고, join 회피로 개별 실행하면 오히려 부하가 커지며, single index 과다로 scan과 정렬이 늘어난다.
  • 인덱스 예: (user_id, expired_time) 복합 인덱스가 필요한데 각각 single index로 만들어져 있었고, admin 필터 대응으로 컬럼마다 single index를 만든 경우도 있었다.
  • OR와 옵티마이저 함정: expired_time에 NULL 대신 default(9999-12-31)를 주면 OR를 제거할 수 있고, ORDER BY single-index-column DESC LIMIT 조합이 잘못된 인덱스로 full scan을 유발하는 이슈를 확인했다.
  • schema 부채: flag성 컬럼까지 longtext를 쓰고, auto increment int PK가 한계에 임박했으며, varchar size 255 남발, sql_mode 미적용, 복제용 binlog_format 미설정 상태였다.
  • 미사용 인덱스: performance_schema.table_io_waits_summary_by_index_usage에서 COUNT_STAR=0인 인덱스를 찾아 제거 대상을 선별했다.
  • export 병렬화: information_schema.files로 테이블별 크기를 뽑아 평균에 맞춰 mysqldump를 병렬 실행하고, utf8mb4와 set-gtid-purged=OFF 등 옵션으로 문자 깨짐을 막았다.
  • 전송과 import: mysqldump를 tar와 nc(netcat) 파이프라인으로 전송하고, import도 크기 짝을 맞춰 병렬 실행하며 대형 단일 테이블은 INSERT 라인을 awk로 나눠 병렬 적재했다.
  • 복제 시간 단축: innodb_flush_log_at_trx_commit이 기본 1이면 DML 많은 서비스에서 sync가 끝나지 않아 0이나 2로 바꿔야 하며, 인덱스는 데이터 적재 후 ALTER 한 번으로 생성해 scan을 1회로 줄였다.
  • schema 수정: 이전 시 부적절한 longtext 제거, AI PK를 int에서 bigint로, varchar 축소, enum 제거, 불필요 인덱스 제거, characterSet과 collation 제거를 함께 적용했다.
  • GCP 복제 특성: source writer 직접 연결이 불가해 onPremisesConfiguration으로 External source instance를 sqladmin REST API로 생성하고, demote는 콘솔 미지원이라 golang SDK로 SkipReplicationSetup 등을 지정해 수행했다.
  • 복제 오류 방지: binlog_format=ROW에서 writer와 reader 컬럼 타입이 다르면 복제가 실패해 replica_type_conversions를 ALL_LOSSY, ALL_NON_LOSSY로 설정했다.
  • 실행 절차: 점검 시작, 구 writer read_only, Cloud SQL reader promote, 도메인 IP 교체, 구 writer session 정리와 stop, service open 순으로 2분 내외 다운타임을 목표했다.
  • 장애와 대응: STRICT_TRANS_TABLES로 varchar 초과가 warning에서 error가 된 건 정상이었고, prefer_ordering_index=off 전역 적용이 SELECT ORDER BY id DESC LIMIT을 full scan으로 만들어 롤백 후 쿼리별 SET_VAR 힌트로 대응했다.
  • 이후 평가: Cloud SQL은 query insight로 전체 쿼리 확인이 쉽고 core 대비 memory 지정이 유연한 장점이 있으나, 대용량 DDL 복제 지연(gh-ost 사용)과 HA 추가 인스턴스 비용, 클러스터 간 복제의 비직관성은 단점이었다.
왜 읽나public cloud 간 MySQL 이전을 유료 솔루션 없이 다운타임과 비용 최소로 수행하려는 DBA/백엔드 엔지니어에게 실전 절차와 함정 레퍼런스.
매스프레소(콴다)
매스프레소(콴다) 블로그
원문은 여기서 이어서 읽을 수 있어요
원문 읽기
읽음 (0)

이 글과 비슷한

  1. DB / 데이터·spotify-engSpotify Engineering·

    데이터 레이크 온라인 포인트 쿼리 인덱싱 — RAP

    Spotify 엔지니어링이 페타바이트 규모 데이터 레이크(GCS)에 저장된 Parquet 파일에서 한 자릿수 밀리초 레이턴시로 포인트 쿼리를 수행하는 RAP(Random Access Parquet) 방식을 공개했다. Trino·BigQuery 같은 분산 SQL 엔진은 단일 행 조회도 스케줄링·플래닝 비용으로 수 초가 걸리지만, RAP는 외부 인덱스로 키→(파일, 행 번호)를 직접 매핑해 의존적 read chain을 병렬화함으로써 이 문제를 해결했다. 기존 KV 스토어(Bigtable)와 달리 GB당 비용이 클라우드 스토리지 read 수준에 불과해 장기 이력 데이터나 롱테일 피처도 인터랙티브 조회 대상이 된다.

    #data-engineering#indexing#data-lake+2
  2. DB / 데이터·여기어때 (GC컴퍼니)여기어때 (GC컴퍼니)·

    데이터 통합— MongoDB 원칙으로 document를 통합하고 동기화를 재설계하다 (3/3)

    여기어때 전시개발팀은 ES 단일 대문서 → MongoDB v1 RDB 1:1 파편화 → v2 도메인 단위 통합이라는 세 차례 구조 전환을 거쳐 전체 동기화 시간을 약 1시간에서 10분으로 단축했다. 이 글은 3부작의 마지막으로, v2 통합 문서 구조에 맞춰 "$set/$unset 필드 단위 부분 갱신 + 이벤트 발행" 기반 동기화를 어떻게 재설계했는지 구체적인 MongoDB 패턴과 함께 설명한다.

    #denormalization#data-sync#mongodb+2
  3. DB / 데이터·pinterest-engPinterest Engineering·

    Pinterest 차세대 DB 수집 프레임워크의 자동화된 스키마 진화

    Pinterest의 CDC 기반 DB 수집 파이프라인은 MySQL에서 Kafka, Flink, Spark, Iceberg를 거치는 다층 구조다. 스키마 변경이 생기면 모든 계층을 동시에 업데이트해야 해 드리프트, 배포 실패, 데이터 불일치가 반복됐다. Pinterest 엔지니어링 팀은 이를 해결하기 위해 가산적 변경만 자동화하는 스키마 진화 프레임워크를 구축하고, PR 기반 롤아웃과 SLA 기반 일관성 모델을 도입했다.

    #data-pipeline#apache-flink#cdc+2