배경 상황
최근 사내에서 stg 환경 구성에 대한 논의가 있었다. 기존 서비스가 운영되는 ECS 환경에서 스테이징용 ECS 서비스 배포는 대부분 되어있었는데, 실제로는 거의 사용하지 않거나 stg라고 보기에는 애매한(개발환경과 거의 동일하거나 stg에서 운영DB를 바라본다던가) 구성으로 되어있었다고. 그래서 stg환경을 제대로 운영해보자! 라는 이야기가 나왔고, 외부 API 연동과 같은 부분은 차차 하더라도 서버와 DB는 빠르게 스테이징 환경을 구성하기로 했다.
운영DB의 데이터를 스테이징 환경에 옮기는 방법으로는 크게 두 가지를 고민했었다.
- mysqldump로 DB데이터를 덤프 떠서 stg 환경에 밀어넣기
- DB 데이터 복제 서비스 (ex. AWS DMS, Debezium과 같은 오픈소스 직접 활용 등)
첫번째 방법이 좀 더 간단하지만 로컬 환경에 떠서 옮기는 형태라 데이터 볼륨이 꽤 있는 현재 DB(RDB인데 blob 데이터를 저장하는 컬럼이 꽤 많았다)는 옮기는 데에 시간이 오래 걸릴 듯 했다. 도중에 깜빡하고 끄거나 자원이 모자라거나 했을 때 문제가 생길 수도 있고, 내가 DB를 아주 잘 아는 게 아니라서 마이그레이션 전 & 도중에도 문제가 생기면 어디에서 문제가 발생하는지 쉽게 확인할 수 있는 AWS DMS 서비스를 활용하는게 조금 더 안전하다고 판단해서 DMS로 구성하기로.
DMS는 크게 full load, full load 후 CDC, CDC 세 종류의 작업을 지원하는데 이번 구성에는 CDC 기능은 필요 없고 요청 할 때마다 신규 데이터를 밀어 넣어주면 되어서 CDC 기능 활용시의 제약사항은 고려하지 않았다.
AWS DMS(Database Migration Service)란?

이름 그대로 데이터베이스를 마이그레이션하기 위한 AWS 서비스이다.
다양한 OLTP 데이터베이스 간의 마이그레이션 뿐만 아니라(온프레미스 → 클라우드도 지원한다) OLTP > OLAB(Redshift)로의 마이그레이션, RDB → S3로의 마이그레이션 등도 지원한다. 또한 AWS SCT라는 툴을 활용하면 이기종 간의 마이그레이션도 가능하다(가능하다고 했지 쉽다고는 안했다).
AWS DMS로 Staging DB 구성하기
사용하는 DB 엔진이 MySQL이어서 DMS 구성할 때에는 뱅크샐러드 블로그를 많이 참고했다.
사전 작업
초기 세팅의 경우 source DB의 스키마를 export해서 target DB에 import 해준다. 이렇게 하는 이유는 DMS가 Auto Increment나 FK 등의 제약조건을 자동으로 생성하지 않기 때문에 스키마 구조를 미리 잡아주고 마이그레이션을 진행해야하기 때문이다. 초기 스키마만 세팅해두면 다음번에는 스키마는 그대로 두고 데이터만 삭제했다가 집어 넣는 truncate 모드로 DMS를 실행해주면 된다.
1. mysqldump를 이용해서 마이그레이션 하고자 하는 데이터베이스의 스키마를 추출한다(mysqldump는 mysql client를 다운로드 받으면 함께 설치되는 유틸리티). 아래 명령어 중 이 중 --databases 플래그는 특정 스키마(데이터베이스)만 추출하기 위한 옵션이다.
mysqldump -h <소스DB 엔드포인트 주소> -P <db 포트> -u <db 유저> -p --no-data --set-gtid-purged=OFF --databases <대상 DB> > schema.sql
2. 위에서 추출한 파일을 이용해 target DB에 대한 스키마를 생성해준다.
mysql -h <타겟DB 엔드포인트 주소> -P <db 포트> -u <db 유저> -p < schema.sql
그리고 마이그레이션 시 DMS에서 replication instance(복제 작업을 진행하는 인스턴스라고 보면 된다)가 실행될 서브넷 그룹을 지정해야하는데, 해당 task의 경우 source와 target DB 모두 접근 가능해야하므로 퍼블릭 서브넷에 DB가 배포된 것이 아니라면(당연히 하면 안됨) 각 DB가 배포된 서브넷 간의 네트워크 구성을 진행해주어야 한다. VPC Peering 혹은 Transit Gateway로 각 서브넷을 연결해야하는데, 보안 그룹도 구성해야하기 때문에 Transit Gateway를 구성한다면 security group referencing 기능은 활성화 하기를 추천(24년 9월에 GA 된 기능).
DMS으로 MySQL DB 마이그레이션하기
위 사전 구성을 진행했다면 이제 본격적으로 DMS 구성을 진행해보자.
1. AWS DMS > Subnet groups를 선택하고, Create subnet group을 클릭해 DMS subnet 그룹을 생성한다. 위에서 설명했듯 복제 인스턴스가 실행될 서브넷을 구성해주는 작업이라고 보면 된다.

2. subnet 그룹의 이름과 설명을 설정한다. 그리고 VPC의 경우에는 source/target DB에 모두 접근이 가능한 VPC를 선택하고, subnet도 마찬가지로 source/target DB 접근이 가능한 subnet으로 선택해주고 subnet group을 생성한다.

3. 다음으로는 replication task를 위한 보안그룹을 생성한다. VPC는 위에서 subnet group을 생성할 때 선택했던 VPC를 선택하고, 소스는 sourceDB가 배포된 subnet과 targetDB가 배포된 subnet을 선택한다.
- 참고: Transit Gateway에서 security group referencing을 활성화했다면 각 DB의 보안그룹을 선택할 수 있고, 활성화 하지 않았다면 해당하는 subnet의 IP prefix를 직접 입력해 구성한다.

4. DMS task를 생성하기 위해 복제 인스턴스(replication instance)를 생성한다. AWS DMS > Migrate or replicate > Provisioned instances > Create replication instance를 클릭한다.

5. 복제 인스턴스 이름과 설명을 설정한다.
- instance class: 복제 인스턴스의 스펙을 설정(빠르게 작업을 끝내기 위해서 다소 높은 인스턴스를 선택)
- Engine version: 최신 버전 선택(복제 인스턴스의 버전으로 DB 엔진 버전과는 별개)
- High Availability: Single-AZ(빠르게 full load만 하고 종료할거기도 하고 문제가 생기면 재로드하면 되기 때문)

6. 스토리지 용량은 작업 속도에 영향을 주기 때문에 실제 DB 스토리지 용량보다 다소 넉넉하게 설정한다. Connectivity and security 탭에서는 아래와 같이 복제 인스턴스의 네트워크를 구성한다.
- VPC: DMS subnet group의 VPC를 선택
- replication subnet group: 위에서 생성한 DMS subnet group을 선택
- public accessible: 체크박스 해제(애초에 DB라면 private subnet에서 생성했을 것이기 때문)
- VPC security group: 위에서 설정한 보안그룹을 설정
- Maintenance: CDC를 사용하거나 오랜 기간 DMS를 사용하는 경우 automatic version upgrade에 의해 task가 중지될 수 있기 때문에 주의하여 설정

7. Source DB와의 연결을 위해 Source Endpoint를 생성한다. AWS DMS > Migrate or replicate > Endpoints에서 Create endpoint를 클릭한다. Endpoint Type은 Source endpoint로 설정하고 Select RDS DB instance를 선택해 복제할 RDS 인스턴스 정보를 불러온다.

8. Endpoint configuration에서 자동으로 입력되는 부분은 그대로 두고, Access to endpoint database에서 적절한 방법을 선택한다.

9. Server name 및 기본적으로 입력되는 부분은 그대로 두고, Password를 입력한 후 Endpoint를 생성한다. 생성 후에는 Test connections 를 통해 연결이 제대로 설정되었는지 확인한다.

10. Target Endpoint도 위와 동일한 요령으로 생성하되, targetDB의 정보를 입력해준다. 그 다음 추가로 설정해줄 점이 있는데, Endpoint settings라는 토글을 열고, Use endpoint connection attributes를 체크한다. 그 다음 아래 값을 Extra connection attributes에 입력해 FK 제약 조건 관련 에러를 방지한다.
initstmt=SET FOREIGN_KEY_CHECKS=0

11. 이제 Database Migration Task를 아래와 같이 생성해 데이터 마이그레이션을 진행해보자.
- Task identifier: test-dms-task 등 적절한 이름으로 설정
- Replication Instance: 위에서 생성한 replication instance
- Source DB Endpoint: 위에서 생성한 endpoint
- Target DB Endpoint: 위에서 생성한 endpoint

- Task mode: Provisioned 선택 및 위에서 생성한 인스턴스 선택
- Migration type: Migrate existing data (데이터 full load만 진행하고 CDC는 하지 않겠다는 옵션)

- Editing mode: Wizard
- Target table preparation mode: Truncate (데이터 스키마는 유지하고 데이터만 삭제 후 마이그레이션 작업 진행)
- LOB column settings: Full LOB mode (blob 데이터 컬럼이 있을 경우 해당 설정을 하지 않으면 데이터가 중간에 잘려서 에러 발생할 수 있음)

- Data validation: Validation with data migration

- Table mappings: 아래와 같이 시스템 DB를 제외한 나머지 데이터베이스를 이관

{
"rules": [
{
"rule-type": "selection",
"rule-id": "1",
"rule-name": "exclude-system-schemas",
"object-locator": {
"schema-name": "mysql",
"table-name": "%"
},
"rule-action": "exclude",
"filters": []
},
{
"rule-type": "selection",
"rule-id": "2",
"rule-name": "exclude-information-schema",
"object-locator": {
"schema-name": "information_schema",
"table-name": "%"
},
"rule-action": "exclude",
"filters": []
},
{
"rule-type": "selection",
"rule-id": "3",
"rule-name": "exclude-performance-schema",
"object-locator": {
"schema-name": "performance_schema",
"table-name": "%"
},
"rule-action": "exclude",
"filters": []
},
{
"rule-type": "selection",
"rule-id": "4",
"rule-name": "exclude-sys-schema",
"object-locator": {
"schema-name": "sys",
"table-name": "%"
},
"rule-action": "exclude",
"filters": []
},
{
"rule-type": "selection",
"rule-id": "290271142",
"rule-name": "290271142",
"object-locator": {
"schema-name": "%",
"table-name": "%"
},
"rule-action": "include",
"filters": []
}
]
}
- Start migration task: Manually later
- Premigration assessment 항목에서는 Turn on premigration assessment를 활성화하고 결과를 저장할 S3 및 IAM Role을 구성

12. Premigration assessments를 활성화 하게 되면 DMS 마이그레이션 작업 실행 시 문제가 될 부분들을 미리 알려준다. 이 중에서 평가 결과가 Failed / Warning 인 항목들은 내용을 자세히 살펴보자. 내가 마이그레이션 했을 당시 Failed 혹은 Warning이 떴던 항목들은 다음과 같았다.
- Validate if table has primary key or unique index when DMS validation is enabled: CDC 작업의 유효성 검사 시 문제가 되는 부분으로 크게 신경쓰지 않아도 되어서 따로 조치를 취하지는 않았다.
- Validate if source tables in the task scope have cascade constraints: 소스 테이블에 케스케이드 제약조건이 있는지 확인하는 항목으로 DMS는 이 제약조건을 마이그레이션 해주지 않는다. 하지만 위와 같이 구성하면 스키마를 미리 구성해서 적용하기 때문에 크게 신경쓰지 않아도 된다.
- Validate if the timeout values are appropriate for a MySQL source or target: 복제 중 연결 끊김을 방지하기 위한 항목으로 net_read_timeout, net_write_timeout, wait_timeout 파라미터들이 5분(300초) 미만으로 설정되어있을 경우 검사에서 걸리게 된다. 해당 값들은 parameter group에서 수정할 수 있고 Dynamic한 파라미터이기 때문에 DB인스턴스 재시작 없이 적용할 수 있다.
- 지원되지 않는 데이터 유형: DMS에서는 float 타입의 경우 -1.79E+308~-2.23E-308, 0, 그리고 2.23E-308~1.79E+308 이내의 값만 허용한다. 해당되는 컬럼이 해당 범위 내의 값만 가지고 있어 해당 내용도 별도 조치 없이 진행했다.
- Validate if auto-increment is enabled on any tables used for migration: DMS가 auto-increment 설정을 마이그레이션 해주지 않기 때문에 뜨는 항목이고 케스케이드 제약조건과 마찬가지로 스키마를 미리 구성하고 마이그레이션하면 문제 없다.
- Validate if secondary indexes are enabled during full load on the target database: full load 시 마이그레이션 성능에 영향이 갈 수 있는 부분으로 마이그레이션 자체가 실패하지는 않기 때문에 따로 조치하지 않았다.
- LOB 컬럼에 NOT NULL 조건 걸려 있는 경우: 해당 경우에는 DMS 작업을 수행할 수 없기 때문에 assessment 결과에서 나온 테이블/컬럼을 Nullable하게 변경 후 마이그레이션을 진행해야한다. 마이그레이션이 완료되면 다시 NOT NULL 조건을 설정한다.
- 기타 MySQL assessment 항목을 보고싶다면 다음 링크를 참조하면 된다.