Insight
home
News
home

AWS DMS를 활용한 데이터베이스 마이그레이션 및 대규모 스키마 변경기

날짜
2026/02/25
안녕하세요, 백엔드 엔지니어링 팀입니다. 최근 저희 서비스는 기분 좋은 비명을 지르고 있습니다. 2022년 '새로운 매쓰플랫'을 오픈한 지 불과 4년 만에, 서비스 이용량이 가파르게 상승하며 데이터 규모가 상상 이상으로 커졌기 때문입니다. 특히 학원 선생님들께서 학생들을 위해 생성하신 학습지에 포함된 문제수가 어느덧 20억 건을 돌파했습니다. 서비스의 가파른 성장은 팀에게 큰 보람이지만, 동시에 기술적인 '시한폭탄'을 마주하게 했습니다. 바로 해당 문제 데이터들이 저장되는 주요 테이블의 ID 컬럼(Int)이 허용하는 최대치(약 21억)에 임박했다는 점이었습니다. 이 문제를 해결하기 위해 진행한 전체 서비스의 주요 테이블 컬럼 타입 변경(IntBigint)과 AWS DMS(Database Migration Service)를 활용한 대규모 마이그레이션 여정을 공유합니다.

1. AWS DMS란 무엇인가?

본격적인 작업기에 앞서, 이번 프로젝트의 핵심 도구인 AWS DMS에 대해 간단히 짚고 넘어가겠습니다. AWS Database Migration Service(DMS)는 데이터베이스를 AWS로 쉽고 안전하게 마이그레이션할 수 있도록 도와주는 클라우드 서비스입니다. 단순히 데이터를 옮기는 것을 넘어, 마이그레이션 중에도 소스 데이터베이스가 정상 운영될 수 있도록 실시간 복제(CDC, Change Data Capture) 기능을 제공하는 것이 가장 큰 특징입니다.

DMS의 핵심 아키텍처

DMS는 크게 세 가지 구성 요소로 작동합니다.
1.
Source/Target Endpoint: 데이터베이스의 접속 정보를 담고 있는 연결 지점입니다.
2.
Replication Instance: 데이터를 추출하고 타겟에 적재하는 실제 계산 리소스(EC2 기반)입니다.
3.
Replication Task: 어떤 데이터를 어떻게 옮길지 정의한 작업 단위입니다.

2. 우리가 해결해야 했던 과제

단순한 DB 이전이라면 스냅샷 복구만으로 충분했겠지만, 이번 작업에는 몇 가지 까다로운 조건이 있었습니다.
성장의 속도를 따라잡는 스키마 변경: 매일 엄청난 양의 문제가 학습지로 생성되는 상황에서, 데이터 이전과 동시에 ID 타입을 Bigint로 변환해야 했습니다.
제약 조건 정리: DMS 작업의 병목이 될 수 있는 Cascade, Trigger, 불필요한 FK를 사전에 정리해야 했습니다.
다운타임 최소화: 실시간 데이터 동기화(CDC)를 통해 서비스 중단 시간을 최소화해야 했습니다.
전체적인 마이그레이션 진행 단계는 다음과 같습니다.

3. 마이그레이션 전략 및 준비 과정

사전 작업: 데이터베이스 환경 최적화

DMS는 소스 DB의 로그를 읽어 타겟 DB로 전달합니다. 이를 위해 소스 DB(Aurora MySQL)에서 binlog를 활성화하고 형식을 ROW로 설정했습니다. 또한, 마이그레이션 중 발생할 수 있는 데이터 정합성 오류를 방지하기 위해 서비스 코드에서 CascadeTrigger 로직을 제거하고 DB 제약 조건도 함께 삭제했습니다.

타겟 DB 구축 및 스키마 수정

소스 DB의 특정 시점(PITR) 스냅샷을 기반으로 신규 RDS 클러스터를 생성했습니다. 생성 직후, 타겟 DB에서 직접 ALTER TABLE 명령을 통해 ID 컬럼들을 Bigint로 확장하고, 성능을 위해 인덱스를 재구성했습니다.

4. 철저한 검증: 스테이징에서의 무한 리허설

이번 프로젝트의 성패는 "운영 환경에서 예외 상황 없이 동작하는가"에 달려 있었습니다. 이를 위해 실제 전환을 수행하기 전, 스테이징 환경에서 수차례의 리허설과 극한 상황 테스트를 진행했습니다.

[Case Study 1] 숨겨진 의존성 발견: 이름만으로는 알 수 없었던 연결고리

22억 이상의 ID를 주입하자, 컬럼명만으로는 유추할 수 없었던 로그 테이블 등에서 Numeric Overflow 에러가 발생했습니다. 극한 데이터 주입 테스트를 통해 운영 환경의 '시한폭탄'을 사전에 제거했습니다.

[Case Study 2] Virtual Column의 함정: 설계의 교훈

DMS 적재 시 에러를 유발했던 가상 컬럼들을 제외하며, DB 레벨보다는 애플리케이션 엔티티 단에서 계산된 프로퍼티로 구현하는 것이 인프라 변경에 훨씬 유연하다는 교훈을 얻었습니다.

[Case Study 3] PK가 없는 테이블의 역습

PK가 없는 테이블은 DMS 복제 효율을 극도로 떨어뜨립니다. 아무리 조회가 없는 로그성 테이블이라도 나중의 관리와 이전을 위해 UUID와 같은 PK는 무조건 생성해야 한다는 설계 원칙을 다시 세웠습니다.

[Case Study 4] 양날의 검 CASCADE: 편리함 뒤에 숨은 위험

DMS 충돌 위험과 예기치 못한 대규모 연쇄 삭제 리스크를 방지하기 위해 CASCADE 설정을 제거했습니다. 모든 삭제 로직을 애플리케이션 레벨로 이전하여 데이터 가시성과 제어권을 확보했습니다.

[Case Study 5] 마이그레이션의 걸림돌, Foreign Key(FK) 제거

DMS 성능 확보를 위해 타겟 DB에서 모든 FK를 제거했습니다. DB 레벨의 FK보다는 애플리케이션 단에서 필요시 매핑을 관리하는 것이 대규모 인프라 변경 시 유연성을 높이는 방향임을 확인했습니다.

5. AWS DMS 설정 및 실행

본격적인 마이그레이션을 위해 세밀한 DMS 설정이 필요했습니다. 데이터 정합성과 속도라는 두 마리 토끼를 잡기 위해 적용한 핵심 설정들입니다.

엔드포인트 세부 설정

Source Endpoint: 캐릭터셋 손실 방지를 위해 Extra Connection AttributesCHARSET=utf8mb4;를 명시했습니다.
Target Endpoint: 대량 적재 시 병목을 줄이기 위해 ParallelLoadThreads=1 설정을 적용하고, Initstmt=SET FOREIGN_KEY_CHECKS=0;SET NAMES utf8mb4;autocommit=true;를 추가하여 제약 조건 검사를 일시적으로 우회했습니다.

복제 인스턴스(Replication Instance) 및 태스크(Task)

인스턴스 사양: 가용성을 위해 Production workload(Multi-AZ)로 생성했으며, 초기 모델은 dms.r6i.xlarge를 선택했습니다.
LOB 모드: Limited LOB mode를 사용하고 최대 사이즈를 20,000 KB로 설정하여 JSON이나 Text 컬럼 데이터가 잘리지 않도록 했습니다.
태스크 분리: 부하 분산과 모니터링 편의를 위해 mathflat, pod, others 도메인별로 3개의 태스크를 생성하여 병렬로 실행했습니다.

6. 모니터링 및 위기 극복 (Troubleshooting)

실행 단계에서는 예상치 못한 변수들이 발생했습니다. 실시간 모니터링 지표를 기반으로 위기를 극복한 과정입니다.

[Trouble 1] 잘못된 인스턴스 타입 설정

DMS 태스크 실행 직후, 예상보다 동기화 속도가 현저히 느리고 지연이 발생했습니다. 분석 결과, 메모리 최적화형인 r6i 계열이 아닌 컴퓨팅 최적화형인 c6i 계열로 인스턴스가 잘못 생성되어 있었습니다. DMS는 인메모리에서 소스 로그를 처리하는 비중이 높기 때문에 즉시 dms.r6i.xlarge로 교체하여 처리 성능을 정상화했습니다.

[Trouble 2] 리소스 병목과 스케일 업

서비스 피크 타임이 다가오자 CDC 지연(Latency)이 다시 증가하기 시작했습니다. 점검 전 안정적인 처리를 위해 인스턴스를 dms.r6i.4xlarge로 과감하게 상향 조정했습니다. 덕분에 20억 건이 넘는 방대한 문제 데이터셋에서도 실시간 동기화 상태를 유지할 수 있었습니다.

7. 서비스 전환 (Cut-over) 및 안정화

전환 당일 새벽, 약 5시간의 점검 시간을 확보하고 작업을 마무리했습니다.
1.
서비스 차단: 모든 서버의 인스턴스를 0개로 조정하여 데이터 유입을 중단했습니다.
2.
DMS 최종 동기화: 잔여 CDC 데이터를 모두 반영한 후 DMS 태스크를 중지했습니다.
3.
애플리케이션 배포: IntLong 타입 변경 및 신규 데이터베이스 접속 정보가 반영된 코드를 배포했습니다.
4.
사후 배치 실행: 점검 시간 동안 실행되지 못한 예약 배치들을 수동으로 실행했습니다.
5.
집중 모니터링: 약 5시간 이상 실시간 트래픽에 따른 DB 부하와 애플리케이션 로그를 면밀히 살핀 결과, 서비스가 안정적으로 제공되는 것을 확인하고서야 비로소 안심하며 퇴근길에 오를 수 있었습니다.

8. 마치며: 회고와 교훈

이번 마이그레이션 프로젝트는 단순한 데이터 이전을 넘어, 가파르게 성장해온 우리 서비스의 기초 체력을 점검하고 보강하는 귀중한 시간이었습니다. 작업을 마무리하며 얻은 핵심 교훈들을 정리해 봅니다.
DB 제약 조건의 트레이드오프: FKCASCADE는 데이터 정합성 유지에 강력한 도구이지만, 대규모 스키마 변경 시에는 유연성을 저해하는 양날의 검이 될 수 있습니다. 실무에서는 이러한 복잡성을 애플리케이션 레벨로 가져와 명시적으로 관리하는 것이 장기적인 인프라 운영 측면에서 훨씬 유리함을 체감했습니다.
설계의 기본기가 곧 유지보수성: PK 부재나 가상 컬럼 사용과 같은 사소한 설계적 선택이 마이그레이션 시점에는 거대한 비용과 리스크로 돌아올 수 있습니다. 처음부터 UUID와 같은 글로벌 식별자를 보장하고 앱 중심의 로직 설계를 유지하는 '기본기'가 시스템의 영속성을 결정짓습니다.
검증의 가치는 극단에서 나온다: 스테이징 환경에서의 수많은 테스트 중 가장 가치 있었던 것은 '22억 ID 주입'과 같은 극단적인 시나리오 테스트였습니다. 실제 데이터를 넘어 미래에 닥칠 한계 상황을 미리 시뮬레이션함으로써 운영 환경에서의 치명적인 장애를 방지할 수 있었습니다.
우리는 이제 학습지 내 20억 문제라는 거대한 데이터를 담고도 더 큰 성장을 도모할 수 있는 그릇을 마련했습니다. 앞으로도 저희 팀은 고객들에게 끊김 없는 최상의 경험을 제공하기 위해 더욱 견고하고 유연한 기술 아키텍처를 구축해 나갈 것입니다. 긴 글 읽어주셔서 감사합니다!