(3/5) AWS DMS + CDC 로 MSSQL 무중단 컷오버 — 풀로드 후 변경분 따라잡기
📚 MSSQL → AWS RDS 마이그레이션 시리즈 (전체 5편)
- 방법 비교 — 6가지 중에서 고르기
- Native Backup/Restore 실전 — 옵션 그룹부터 컷오버까지
- DMS + CDC 무중단 컷오버 — 풀로드 후 변경분 따라잡기 ← 지금 글
- 변경분 계속 쌓기 — NORECOVERY 체인과 CDC-only 결합
- 정합성 트러블슈팅 — 케이스별 8가지 함정
지난 글에서 Native Backup/Restore 로 풀카피 → 컷오버 순서를 정리했어요. 그런데 운영 DB 라 단 몇 분의 다운타임도 허용 안 되는 케이스가 있죠. 이번 글은 그런 상황에서 쓰는 AWS DMS + CDC 구성법이에요. 원본을 운영 중 그대로 두고 풀로드 → 변경분 실시간 따라잡기 → 컷오버 순서로 다운타임을 분 단위 이하로 줄이는 흐름을 정리합니다.
💡 이 글에서 다루는 것
- CDC 가 처음이라면 — 개념 30초 + Change Tracking 과 차이 + MSSQL 2016 에디션 조건
- 원본 MSSQL 에서 CDC 활성화 (DB 레벨 + 테이블 레벨)
- 켠 CDC 가 진짜 변경을 잡는지 변경 테이블로 눈으로 확인
- DMS Replication Instance / Endpoints / Task 세팅
- Full Load + CDC 동시 모드 vs 분리 모드 차이
- 스키마/인덱스/IDENTITY 는 DMS 가 안 가져온다는 점과 대응
- CloudWatch 로 latency 추적해서 안전하게 컷오버하는 절차
- 마이그레이션 끝난 뒤 CDC/DMS 정리(cleanup)
1. 큰 그림 — 무엇이 어디서 도는가
[내부망 MSSQL]
│ (1) CDC 로 변경분 캡처 (트랜잭션 로그 기반)
│
▼
[DMS Replication Instance (VPC)]
│ (2) Full Load + 캡처된 변경분을 타깃에 적용
│
▼
[AWS RDS for SQL Server]
DMS 는 Replication Instance 라는 EC2 같은 워커를 하나 띄워두고, 거기서 소스의 트랜잭션 로그 를 읽어와 타깃에 흘려줘요. 원본은 CDC 만 켜두면 되고, DMS 가 직접 원본을 폴링하면서 변경을 잡아갑니다.
💡 풀로드 + CDC 를 같은 task 에서 켜면 풀로드 진행 중에도 변경을 캐시해두고, 풀로드 끝나는 순간부터 따라잡기를 시작해요. “다운타임 거의 0” 의 핵심이에요.
2. 원본 MSSQL 준비 — CDC 활성화
DMS 가 MSSQL 의 변경분을 잡아가려면 원본에서 CDC 가 켜져 있어야 해요. SQL Server 의 CDC 는 트랜잭션 로그를 읽어서 변경을 별도 시스템 테이블에 기록하는 기능이에요.
2-1. CDC 가 뭔지부터 — 30초 개념
CDC 를 처음 만지는 분들을 위해 개념만 짧게 짚고 갈게요. CDC(Change Data Capture)는 테이블에 일어난 INSERT/UPDATE/DELETE 를 트랜잭션 로그에서 읽어다가, 별도의 변경 기록 테이블에 차곡차곡 쌓아두는 SQL Server 기본 기능이에요. 원본 테이블에 트리거를 다는 게 아니라, 어차피 기록되는 트랜잭션 로그를 한 번 더 활용하는 방식이라 원본 부하가 작아요.
CDC 를 켜면 SQL Server 가 자동으로 이런 것들을 만들어줘요.
| 생기는 것 | 역할 |
|---|---|
cdc.<schema>_<table>_CT 변경 테이블 |
테이블별 변경 이력이 쌓이는 곳 (예: cdc.dbo_Orders_CT) |
cdc.lsn_time_mapping |
LSN ↔ 시각 매핑. “언제의 변경인지”를 시간으로 환산 |
cdc.<DB>_capture 잡 |
로그를 읽어 변경 테이블에 채우는 SQL Agent 잡 |
cdc.<DB>_cleanup 잡 |
오래된 변경 기록을 자동 삭제 (기본 3일 보존) |
💡 여기서 LSN(Log Sequence Number) 하나만 알고 가면 돼요. 트랜잭션 로그의 각 변경에 매겨진 일련번호예요. DMS 든 CDC-only 시작이든 “이 LSN 이후부터 따라잡아” 라고 좌표를 찍을 때 쓰는 값이에요. 4편의
--cdc-start-position LSN:...이 바로 이거예요.
⚠️ CDC ≠ Change Tracking. 이름이 비슷한 Change Tracking(CT)은 “이 row 가 바뀌었다”는 사실만 가볍게 남기고 옛 값은 안 보관해요. DMS 가 변경분을 실어 나르려면 옛 값·컬럼별 변경까지 들고 있는 CDC 가 필요해요. 둘을 헷갈려서 Change Tracking 만 켜두면 DMS 의 CDC task 가 안 돕니다.
🚨 MSSQL 2016 이면 에디션부터 확인하세요. CDC 는 원래 Enterprise 전용이었는데, SQL Server 2016 SP1 부터 Standard 에디션에서도 풀렸어요. 즉 2016 RTM(SP 미적용) Standard 에선
sp_cdc_enable_db가 막혀요. 켜기 전에 버전·에디션을 먼저 보세요.SELECT SERVERPROPERTY('ProductVersion') AS version, -- 13.0.4001 이상이면 SP1+ SERVERPROPERTY('Edition') AS edition;
13.0.4001.0(SP1) 미만의 Standard 면 SP1 이상으로 올린 뒤에 CDC 를 켜야 해요. Enterprise/Developer 면 RTM 이라도 됩니다.
2-2. DB 레벨 CDC 켜기
USE [MyDB];
EXEC sys.sp_cdc_enable_db;
-- 확인
SELECT name, is_cdc_enabled
FROM sys.databases
WHERE name = 'MyDB';
is_cdc_enabled = 1 이면 OK.
2-3. 테이블 레벨 CDC 켜기
CDC 는 테이블 단위로 한 번 더 켜줘야 해요. 마이그레이션 대상 테이블 전부에 대해 돌립니다.
USE [MyDB];
EXEC sys.sp_cdc_enable_table
@source_schema = N'dbo',
@source_name = N'Orders',
@role_name = NULL, -- 별도 role 안 쓰면 NULL
@supports_net_changes = 1;
테이블 많으면 동적 SQL 로 한 번에 돌려요.
DECLARE @sql NVARCHAR(MAX) = N'';
SELECT @sql = @sql +
N'EXEC sys.sp_cdc_enable_table @source_schema=N''' + s.name
+ N''', @source_name=N''' + t.name
+ N''', @role_name=NULL, @supports_net_changes=1;' + CHAR(13)
FROM sys.tables t
JOIN sys.schemas s ON t.schema_id = s.schema_id
WHERE s.name = 'dbo';
EXEC sp_executesql @sql;
2-4. SQL Server Agent 가 떠 있어야 함
CDC 캡처 잡(cdc.MyDB_capture) 은 SQL Server Agent 가 돌려요. Agent 가 죽어있으면 변경이 안 잡혀요.
EXEC msdb.dbo.sp_help_job @job_name = N'cdc.MyDB_capture';
current_execution_status 가 1 (idle 아닌 실행 중) 또는 정상 스케줄로 도는지 확인하세요.
⚠️ RDS for SQL Server 소스 였다면 CDC 활성화 절차가 조금 달라요(
rds_cdc_enable_db). 이 글은 온프레미스/EC2 소스 기준.
2-5. CDC 가 진짜 잡히는지 눈으로 확인
켜기만 하고 넘어가면 불안하죠. 실제로 변경이 잡히는지 1분이면 확인할 수 있어요. 대상 테이블에 더미 변경을 하나 주고, 변경 테이블을 들여다봅니다.
-- 1) 변경을 하나 발생시키고
UPDATE dbo.Orders SET updated_at = GETDATE() WHERE id = 1;
-- 2) 잠깐(capture 잡 주기, 보통 5초) 뒤 변경 테이블 조회
SELECT TOP 10 __$start_lsn, __$operation, *
FROM cdc.dbo_Orders_CT
ORDER BY __$start_lsn DESC;
__$operation 값의 의미만 알면 돼요.
__$operation |
의미 |
|---|---|
| 1 | DELETE |
| 2 | INSERT |
| 3 | UPDATE (이전 값) |
| 4 | UPDATE (이후 값) |
행이 보이면 CDC 가 살아있는 거예요. ✅ 아무리 기다려도 안 보이면 십중팔구 SQL Server Agent 가 꺼져 있거나(앞 절) capture 잡이 멈춘 거예요.
💡 변경 테이블은
cdc.<DB>_cleanup잡이 기본 3일(4320분) 만 보관하고 지워요. DMS 가 한참 뒤처지거나 task 를 멈춰둔 사이 보존 기간이 지나면 따라잡을 변경분이 날아가니, 따라잡기가 크게 밀릴 땐 보존 주기를 늘려두세요.EXEC sys.sp_cdc_change_job @job_type = N'cleanup', @retention = 5760; -- 4일(분)
2-6. CDC 를 잠깐 껐다 켰다면 — 공백(gap) 대처
실무에서 자주 나오는 상황이에요. “CDC 오버헤드가 부담돼서 잠깐 껐다가 두 시간 뒤에 다시 켰다.” 이러면 그 두 시간 동안의 변경이 어디에도 안 잡혀요. SQL Server CDC 를 sp_cdc_disable_* 로 완전히 끄면 그 사이 트랜잭션 로그는 그냥 truncate 되고, DMS 가 나중에 읽을 변경분이 통째로 사라집니다. 다시 켜면 새 capture instance 가 새 LSN 부터 시작하므로, 공백 구간은 영영 복구되지 않아요.
대처는 “애초에 완전히 끄지 않기” 와 “이미 공백이 생겼다면 재기준화” 두 갈래예요.
① (권장) 오버헤드가 걱정이면 끄지 말고 capture 잡만 멈추기
CDC 기능 자체는 켜둔 채 capture 잡만 멈추면, 그 사이 변경은 트랜잭션 로그에 보존됐다가(log_reuse_wait_desc = REPLICATION) 잡을 다시 켜는 순간 공백 없이 따라잡혀요. 대신 멈춘 동안 로그가 커지니 디스크만 보세요.
-- 멈추기 (오버헤드 잠깐 줄이고 싶을 때)
EXEC sys.sp_cdc_stop_job @job_type = N'capture';
-- 두 시간 뒤 다시 켜기 → 로그에 쌓인 변경을 그대로 따라잡음(공백 없음)
EXEC sys.sp_cdc_start_job @job_type = N'capture';
또는 아예 끄는 대신 capture 잡 부하를 낮추는 방법도 있어요(폴링 간격↑, 배치 축소).
EXEC sys.sp_cdc_change_job @job_type = N'capture',
@pollinginterval = 10, -- 기본 5초 → 10초
@maxtrans = 500; -- 한 번에 처리할 트랜잭션 수 축소
② 이미 완전히 껐다 켜서 공백이 생겼다면 — 해당 테이블 재기준화
두 시간 공백은 CDC 로는 못 메꿔요. 영향받은 테이블만 풀로드 한 번 더(reload) 해서 타깃을 현재 스냅샷으로 다시 맞춘 뒤, 그 지점부터 CDC 를 재개하는 게 가장 안전해요.
- DMS task 중지
- 원본 CDC 재활성화 (
sp_cdc_enable_table) — 새 capture instance 생성 - DMS 콘솔의 Table statistics → 해당 테이블 Reload (영향 테이블만 풀로드 재실행)
- reload 끝나면 CDC 재개 → 이후 변경분은 새 LSN 부터 정상 추적
- 마지막에 5편의 행 수 ·
CHECKSUM_AGG로 공백 구간 메꿔졌는지 확인
⚠️
updated_at같은 워터마크 컬럼이 있으면 그 구간만 골라 MERGE 로 메꾸고 싶을 수 있는데, 그 방식은 DELETE 를 못 잡아요. 공백 동안 삭제된 행이 타깃에 남아버리니, 안전을 원하면 워터마크 catch-up 보다 테이블 reload 를 택하세요.
3. AWS 측 사전 세팅 — Replication Instance / Endpoints
3-1. Replication Subnet Group + Instance
aws dms create-replication-subnet-group \
--replication-subnet-group-identifier dms-subnet-grp \
--replication-subnet-group-description "DMS subnet group" \
--subnet-ids subnet-aaaa subnet-bbbb
aws dms create-replication-instance \
--replication-instance-identifier dms-mssql-mig \
--replication-instance-class dms.r5.large \
--allocated-storage 100 \
--vpc-security-group-ids sg-xxxxxxxx \
--replication-subnet-group-identifier dms-subnet-grp \
--no-publicly-accessible \
--multi-az
인스턴스 사이즈는 풀로드 데이터량/병렬도/CDC 부하 따라 골라요. 보통 dms.r5.large 부터 시작해서 latency 보면서 키워요.
3-2. Source / Target Endpoints
Source (내부망 MSSQL) — S2S VPN 으로 접근.
aws dms create-endpoint \
--endpoint-identifier mssql-source \
--endpoint-type source \
--engine-name sqlserver \
--server-name 10.x.x.x \
--port 1433 \
--database-name MyDB \
--username dms_user \
--password '<DMS_USER_PASSWORD>'
Target (AWS RDS for SQL Server)
aws dms create-endpoint \
--endpoint-identifier rds-target \
--endpoint-type target \
--engine-name sqlserver \
--server-name my-mssql-rds.xxxx.ap-northeast-2.rds.amazonaws.com \
--port 1433 \
--database-name MyDB \
--username admin \
--password '<RDS_ADMIN_PASSWORD>'
3-3. Connection 테스트
엔드포인트를 만들면 반드시 한 번 테스트.
aws dms test-connection \
--replication-instance-arn arn:aws:dms:ap-northeast-2:123456789012:rep:DMS-MSSQL-MIG \
--endpoint-arn arn:aws:dms:ap-northeast-2:123456789012:endpoint:MSSQL-SOURCE
✅ 결과가 successful 이어야 다음 단계로 갈 수 있어요. 실패 사유는 콘솔의 Last failure message 에 떨어져요.
3-4. 소스 계정 권한
dms_user 에는 최소 권한만. 흔히 깨지는 권한 세트는 다음 세 가지에요.
USE master;
GRANT VIEW SERVER STATE TO dms_user;
USE MyDB;
EXEC sp_addrolemember 'db_owner', 'dms_user';
-- 또는 SELECT + VIEW DATABASE STATE + db_datareader 조합
DMS 가 CDC 함수(fn_cdc_get_all_changes_*) 를 호출해야 해서 단순 db_datareader 만으론 부족해요. db_owner 가 가장 깔끔하지만, 보안상 줄이고 싶다면 EXECUTE 권한을 CDC 함수에 별도 부여하는 방식이 있어요.
4. 스키마는 따로 — DMS 가 안 챙기는 것들
🚨 여기서 가장 많이 헷갈려요. DMS 는 데이터 위주 로 옮기는 서비스라, 다음을 직접 챙겨야 해요.
| 항목 | DMS 가 옮겨주나? |
|---|---|
| 테이블 구조 (CREATE TABLE) | △ (기본 타입 변환만, 추천 X) |
| 인덱스 (clustered/nonclustered) | ❌ |
| 외래키 제약 | ❌ (풀로드 중 자동 disable 권장) |
| 트리거 / 저장 프로시저 / 함수 | ❌ |
| 시퀀스 / IDENTITY 시드 | ❌ |
| 사용자/로그인/권한 | ❌ |
일반적인 대응 패턴
- 원본에서
SqlPackage /Action:Extract로 DACPAC 만들기 (스키마만, 데이터 X) - 타깃 RDS 에
SqlPackage /Action:Publish로 스키마 먼저 적용 - 그 다음 DMS 로 데이터만 채우기
- DMS 끝난 후 외래키 / 트리거 / 시퀀스 시드 보정
또는 SSMS 의 “Generate Scripts” 로 스키마 + 보조 객체 만 추출해도 OK.
💡 풀로드 중에는 타깃의 외래키와 인덱스를 잠시 끄거나 비활성화 하는 게 빨라요. Task 설정의
Target metadata에서BatchApplyEnabled+ 인덱스/제약 처리를 조정할 수 있어요.
5. Migration Task 만들기
이제 본 task. Full Load + CDC 모드로 만들고, table mapping 으로 옮길 테이블을 지정해요.
5-1. Table mappings (table-mappings.json)
{
"rules": [
{
"rule-type": "selection",
"rule-id": "1",
"rule-name": "select-dbo",
"object-locator": {
"schema-name": "dbo",
"table-name": "%"
},
"rule-action": "include"
}
]
}
dbo 스키마의 모든 테이블을 선택. 일부만 옮길 거면 table-name 을 구체적으로.
5-2. Task settings (task-settings.json)
{
"TargetMetadata": {
"BatchApplyEnabled": true,
"ParallelLoadThreads": 8,
"ParallelLoadBufferSize": 500
},
"FullLoadSettings": {
"TargetTablePrepMode": "TRUNCATE_BEFORE_LOAD",
"MaxFullLoadSubTasks": 8,
"CommitRate": 10000
},
"Logging": {
"EnableLogging": true,
"LogComponents": [
{ "Id": "SOURCE_CAPTURE", "Severity": "LOGGER_SEVERITY_DEFAULT" },
{ "Id": "SOURCE_UNLOAD", "Severity": "LOGGER_SEVERITY_DEFAULT" },
{ "Id": "TARGET_APPLY", "Severity": "LOGGER_SEVERITY_DEFAULT" },
{ "Id": "TARGET_LOAD", "Severity": "LOGGER_SEVERITY_DEFAULT" }
]
},
"ChangeProcessingTuning": {
"BatchApplyPreserveTransaction": true,
"BatchApplyTimeoutMin": 1,
"BatchApplyTimeoutMax": 30,
"MinTransactionSize": 1000
}
}
| 항목 | 의미 |
|---|---|
BatchApplyEnabled |
변경을 배치로 묶어 타깃에 적용. CDC 단계에서 처리량 ↑ |
ParallelLoadThreads |
테이블당 병렬 스레드 |
MaxFullLoadSubTasks |
동시에 풀로드 돌릴 테이블 수 |
TargetTablePrepMode = TRUNCATE_BEFORE_LOAD |
풀로드 전 타깃 테이블 비우기. 단, 외래키 있으면 실패할 수 있어 사전 작업 필요 |
CommitRate |
풀로드 커밋 단위. 트랜잭션 로그 부담 조절 |
5-3. Task 생성
aws dms create-replication-task \
--replication-task-identifier mssql-fullload-cdc \
--source-endpoint-arn arn:aws:dms:...:MSSQL-SOURCE \
--target-endpoint-arn arn:aws:dms:...:RDS-TARGET \
--replication-instance-arn arn:aws:dms:...:DMS-MSSQL-MIG \
--migration-type full-load-and-cdc \
--table-mappings file://table-mappings.json \
--replication-task-settings file://task-settings.json
# 시작
aws dms start-replication-task \
--replication-task-arn arn:aws:dms:...:task:MSSQL-FULLLOAD-CDC \
--start-replication-task-type start-replication
💡
full-load-and-cdc가 핵심.full-load만이면 풀로드 끝난 시점부터의 변경이 누락돼요.
6. 진행 모니터링 — 무엇을 봐야 하는가
6-1. Task 통계
콘솔에서 Task 의 Table statistics 탭이 가장 직관적이에요. 테이블별로
Full load rows/TotalInserts / Updates / Deletes(CDC 단계)Load state(Table completed,Before load,Full load,Table error)
6-2. CloudWatch 핵심 지표
| 지표 | 의미 | 컷오버 기준 |
|---|---|---|
CDCLatencySource |
소스 트랜잭션 로그 → DMS 까지 지연 (초) | 1초 이내 안정 |
CDCLatencyTarget |
DMS → 타깃 반영까지 지연 (초) | 1~3초 이내 안정 |
CDCIncomingChanges |
캡처 중인 변경 수 | 누적 안 쌓이고 평탄 |
CDCChangesMemorySource |
메모리에 쌓인 변경 | 안정적으로 낮게 |
CDCChangesDiskSource |
디스크로 떨어진 변경 | 0 근처 유지 |
✅ 컷오버 직전 체크 — CDCLatencyTarget 이 연속 5~10분간 1~3초 이내 유지되면 따라잡기 안정 상태로 봐도 됩니다.
⚠️
CDCLatencyTarget이 점점 커지면 DMS 인스턴스 사양 / 타깃 디스크 IOPS / 타깃 인덱스가 병목. 이 상태로 컷오버하면 안 됩니다.
7. 컷오버 절차 — 다운타임 분 단위 이하로
여기서부터가 본 게임이에요. 절차는 한 줄도 빼먹지 마세요.
Step 1. 사전 정렬
- CDC latency 가 안정적으로 작음 (5~10분 연속)
- Table statistics 의 에러 0
- 타깃에 인덱스/외래키 보조 객체 사전 생성 완료 (또는 사전 비활성)
- 애플리케이션 측 새 접속 정보(RDS 엔드포인트) 준비 완료
Step 2. 원본 쓰기 차단
가장 안전한 방법은 애플리케이션 측에서 새 트랜잭션을 막는 거예요. DB 단에서 막으려면
-- 원본 MSSQL
ALTER DATABASE [MyDB] SET READ_ONLY WITH ROLLBACK IMMEDIATE;
또는 앱 계정의 권한을 일시적으로 회수.
Step 3. 마지막 변경분 따라잡기 대기
CDCLatencyTarget → 0 으로 수렴
CDCIncomingChanges → 0 으로 수렴
10~30초 정도면 보통 마지막 트랜잭션까지 다 따라잡아요.
Step 4. 검증
-- 양쪽 row count 비교
SELECT COUNT(*) FROM dbo.Orders; -- 원본
SELECT COUNT(*) FROM dbo.Orders; -- 타깃
-- 최신 데이터 비교
SELECT MAX(updated_at) FROM dbo.Orders;
핵심 테이블 몇 개만 빠르게 비교.
Step 5. 외래키/시퀀스/IDENTITY 복구
-- 외래키 다시 enable
ALTER TABLE dbo.Orders WITH CHECK CHECK CONSTRAINT ALL;
-- IDENTITY 시드 재설정 (원본의 최댓값으로)
DBCC CHECKIDENT('dbo.Orders', RESEED, <원본 MAX(id)>);
Step 6. 앱 connection string 전환
DNS 변경 or config 핫스왑. 새 쿼리는 RDS 로 흐름.
Step 7. Task 중지
aws dms stop-replication-task --replication-task-arn arn:aws:dms:...:task:MSSQL-FULLLOAD-CDC
🎉 컷오버 완료. 다운타임은 보통 1~3분 안에 끝나요.
8. 사후 정리 — 비싸게 두지 말기
DMS Replication Instance 는 시간당 요금이 꾸준히 나와요. 컷오버 끝나면 빠르게 정리하세요.
# 1. Task 삭제
aws dms delete-replication-task --replication-task-arn ...
# 2. Endpoints 삭제
aws dms delete-endpoint --endpoint-arn arn:aws:dms:...:endpoint:MSSQL-SOURCE
aws dms delete-endpoint --endpoint-arn arn:aws:dms:...:endpoint:RDS-TARGET
# 3. Replication Instance 삭제
aws dms delete-replication-instance --replication-instance-arn arn:aws:dms:...:rep:DMS-MSSQL-MIG
원본 MSSQL 의 CDC 도 더 이상 필요 없으면 끄세요. 트랜잭션 로그 보존 부담이 줄어요.
USE [MyDB];
-- 테이블별 CDC 끄기
EXEC sys.sp_cdc_disable_table
@source_schema = N'dbo',
@source_name = N'Orders',
@capture_instance = N'all';
-- DB 레벨 CDC 끄기
EXEC sys.sp_cdc_disable_db;
9. 자주 깨지는 함정
저도 한 번씩 다 밟아본 함정들이에요.
- 🚨 CDC 안 켜고 task 시작 →
full-load-and-cdc가CDC source endpoint not configured에러로 죽음 - 🚨 SQL Server Agent 가 꺼져있음 → CDC 캡처 잡이 안 돌아 변경이 누적되다 폭주
- 🚨 타깃에 외래키가 켜진 채 풀로드 → 부모/자식 로드 순서 때문에 실패. 풀로드 전 disable
- 🚨 IDENTITY 시드 미보정 → 컷오버 후 새 INSERT 가 키 충돌
- 🚨 권한 부족 (
VIEW SERVER STATE, CDC 함수EXECUTE) → CDC 단계에서 silent 하게 latency 만 늘어남 - 🚨
CDCLatencyTarget이 점점 커짐 → DMS 인스턴스 / 타깃 IOPS / 인덱스 병목. 이 상태로 컷오버 절대 금지 - 🚨 트랜잭션 로그 폭증 → CDC 가 안 따라잡고 있거나, 풀백업/로그백업 주기가 너무 길어서. log_reuse_wait_desc 확인
10. Native Backup/Restore vs DMS + CDC — 다시 정리
이전 글과 함께 의사결정 표 한 장으로 정리해드릴게요.
| 기준 | Native Backup/Restore | DMS + CDC |
|---|---|---|
| 원본 그대로 보존(인덱스/제약/IDENTITY) | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ (수동 보정 필요) |
| 다운타임 | 분~시간 단위 | 분 단위 이하 |
| 운영 부담/비용 | 낮음 (일회성) | 중간 (Task 가동 시간 비용) |
| 셋업 난이도 | 낮음 | 중간~높음 |
| 추천 시나리오 | “그대로 + 짧은 유지보수 창” | “절대 다운 불가 + 운영 중 이전” |
저희 사내 케이스 기준으로는
- 유지보수 창이 1~2시간 허락 → Native Backup/Restore 단독
- 유지보수 창이 거의 없음 → Native Backup/Restore 로 풀카피 후 DMS 의 CDC-only 모드 로 변경분만 흘려 컷오버
두 번째 패턴이 사실상 베스트에요. 풀로드 비용은 백업/복원으로 절약하고, CDC 만 DMS 로 처리해서 latency 안정화 후 컷오버.
일단 오늘은 여기까지…..
다음 글에서는 이 두 번째 패턴 — 백업/복원 + CDC-only DMS 의 결합을 단계별로 풀어볼게요.
← 이전 글: (2/5) Native Backup/Restore 실전 — 옵션 그룹부터 컷오버까지 | 다음 글 →: (4/5) 변경분 계속 쌓기 — NORECOVERY 체인과 CDC-only 결합