AWS DMS CDC 연동 시 DB 락이 걸리는 원인과 해결법
AWS DMS CDC 연동 시 DB 락이 걸리는 원인과 해결법
AWS DMS(Database Migration Service)를 이용한 CDC(Change Data Capture) 연동 작업, 특히 운영 중인 프로덕션 DB에서 진행할 때는 아찔한 경험을 할 수 있습니다. 저는 최근 대용량 트랜잭션 테이블을 CDC로 실시간 복제하는 과정에서 DB 락(Lock)이 걸려 서비스 지연과 함께 진땀을 뺀 경험이 있습니다. AWS 공식 문서에서는 CDC가 소스 DB에 미치는 영향을 최소화한다고 소개하지만, 실제로는 설정에 따라 예상치 못한 락이 발생할 수 있습니다. 이 글에서는 AWS DMS CDC 연동 중 발생한 DB 락 문제의 실질적인 원인과 해결 방안을 제 경험을 바탕으로 자세히 풀어보겠습니다. CDC 연동으로 고생하고 계신 분들께 실질적인 도움이 되길 바랍니다.
✅ 핵심 원인: 전체 테이블 스캔(Full Load) 단계와 CDC 시작 지점(Start Position) 설정 문제로 인한 레코드 잠금 확장(Record Lock -> Table Lock)
✅ 최우선 해결법: DMS 태스크 생성 시 “Enable Detailed Monitoring” 및 “Transaction Consistency” 옵션을 해제하고, 타임아웃 파라미터를 조정하세요.
✅ 테이블별 분리: 대용량 트랜잭션 테이블은 소스 DB의 트랜잭션 격리 수준(Isolation Level)을 고려하여 개별 태스크로 분리 실행.
✅ 오프라인 전환: 정말 급하다면 유지보수 시간(Maintenance Window)에 Full Load + CDC를 순차적으로 진행.
1. 나의 AWS DMS CDC 삽질 경험 (왜 DB 락에 걸렸나)
프로젝트의 요구사항은 RDS(MySQL)의 주요 주문 테이블을 S3 데이터 레이크로 실시간 동기화하는 것이었습니다. 초기 복제(Full Load)는 순조로웠습니다. 문제는 데이터가 계속 쌓이는 운영 환경에서 발생했습니다. DMS 태스크가 CDC 단계로 전환된 지 약 2시간 후, 갑자기 운영 서비스의 DB CPU가 100%에 육박했고, 특정 INSERT 쿼리가 수 초 이상 지연되기 시작했습니다. DB 콘솔에서 SHOW PROCESSLIST;를 확인해 보니, DMS가 사용하는 복제 세션에서 오래된 SELECT ... FOR UPDATE 형태의 쿼리가 수만 개의 레코드에 대한 잠금(Gap Lock)을 보유하고 있었고, 이게 다른 트랜잭션의 INSERT를 블로킹하고 있었습니다.
왜 이런 일이 발생했을까요? 결론부터 말하면 DMS CDC의 캡처(Capture) 방식과 MySQL의 트랜잭션 격리 수준(REPEATABLE READ)의 상호작용 때문이었습니다. DMS는 내부적으로 소스 DB의 바이너리 로그(Binary Log)를 읽어 변경 데이터를 캡처하지만, 초기 테이블 복제 후 CDC로 전환하는 순간, 소스 DB에 특정 시점의 일관된 스냅샷을 보장하기 위해 임시 테이블에 대한 락을 획득합니다. 이 때, DMS의 MaxFullLoadSubTasks 설정 값이 테이블 수보다 많거나, ParallelLoadThreads 설정이 과도하게 크면 테이블 수준의 락이 아닌 더 넓은 범위의 락(인덱스 레인지 락)으로 확장될 수 있습니다.
가장 큰 실수는 DMS 태스크 생성 시 “Task Timing” 설정에서 “Start task”를 “Start immediately”가 아닌 “Start on a schedule”로 하면서, 특정 시점 이후의 변경 데이터부터 저장하도록 설정한 것이었습니다. 이로 인해 DMS는 지정된 시작 지점의 바이너리 로그 좌표를 찾기 위해 과도한 백필(Backfill) 작업을 수행하며 소스 DB의 과거 트랜잭션 기록들을 읽으면서 락 경합을 유발했습니다.
여기서 실전 팁 하나를 드리자면, DMS 태스크를 처음 생성할 때는 Start immediately를 선택해 현재 시점에서 CDC를 시작하는 것이 가장 안전합니다. 만약 과거 특정 시점부터 복제해야 한다면, 해당 시점이 정확한지 확인한 뒤 시작 시간에 여유를 두는 것이 좋습니다.
2. AWS DMS CDC 연동 시 DB 락이 걸리는 3가지 핵심 원인 분석
단순히 운이 없었다고 넘기기에는 아쉬우니, 기술적으로 왜 이런 일이 발생하는지 정확히 짚고 넘어가겠습니다. 아래는 DMS CDC 연동 중 DB 락이 걸리는 가장 흔한 세 가지 시나리오입니다.
2.1. Full Load 후 CDC 전환 시점의 “스냅샷 락”
가장 흔한 케이스입니다. DMS는 Full Load를 진행하는 동안 테이블의 일관성을 위해 START TRANSACTION WITH CONSISTENT SNAPSHOT과 같은 명령을 사용합니다. 그리고 나서 테이블 복제가 끝나면 CDC로 전환하는데, 이 때 과거 시점의 데이터와 이후 변경 사항을 맞추기 위해 내부적으로 LOCK TABLES 명령을 수행합니다.
- 증상: 주로 특정 테이블 단위가 아닌 DB 전체의 쓰기 작업이 순간적으로 멈추거나, 지연 시간이 급격히 증가합니다.
- 원인: DMS 태스크 설정 중 “Transaction Consistency” 옵션이 활성화된 상태에서, 테이블 수가 많거나 크기가 큰 경우 스냅샷 생성 지연으로 락 유지 시간이 길어집니다.
주의: Transaction Consistency를 해제하면 Full Load 중 변경된 데이터가 누락될 수 있으므로, 해제 후에는 대상 테이블의 전체 행 수와 최종 변경 시간(Last Modified Time)을 사후 검증해야 합니다.
2.2. 바이너리 로그 읽기 포지션 설정 실수 (Start Position)
기존에 동기화하던 태스크를 중단하고 재개할 때, 혹은 태스크를 새로 만들 때 시작 지점(Start Position)을 잘못 지정하면 DMS가 과거의 대량 바이너리 로그를 처음부터 읽어야 합니다.
- 증상: DB의 디스크 I/O가 포화되고, 복제 지연(Lag)이 심해지며, 특정 트랜잭션에 대한 락이 해제되지 않고 대기 현상이 발생합니다.
- 원인: 시간 기반(Time-based) 시작 위치를 지정할 때, 현재 시점과 밀리초 단위의 차이로 인해 DMS가 정확한 좌표를 찾지 못하고 과거 이벤트를 스캔하게 됩니다.
팁: 태스크를 재개해야 한다면 콘솔의 Resume from last stop position을 신뢰하기보다, 안전한 시간대에 새 태스크를 생성하여 현재 시각을 기준으로 시작하는 것이 낫습니다.
2.3. 소스 DB의 트랜잭션 격리 수준과의 충돌
AWS RDS MySQL의 기본 격리 수준은 REPEATABLE READ입니다. 이 경우 DMS가 캡처하는 바이너리 로그 이벤트에는 행 기반(Row-based) 정보뿐만 아니라, 해당 행을 찾기 위한 인덱스 조건이 포함됩니다. 만약 테이블에 적절한 인덱스가 없거나, 인덱스를 잘못 타는 경우 DMS의 SELECT 작업이 넓은 범위의 레코드를 스캔하면서 공유 락(Shared Lock)을 발생시키고, 이는 다른 트랜잭션의 쓰기를 방해합니다.
해결 포인트: 캡처 대상 테이블에는 DMS의 조회 조건에서 자주 사용되는 컬럼을 조합한 복합 인덱스를 추가하세요. 예를 들어 ID와 UPDATED_AT를 함께 사용하는 인덱스가 있으면 레코드 스캔 범위가 크게 줄어듭니다.
3. DB 락 발생 유형별 비교 분석 (상황별 최적 해결책)
어떤 상황에서 어떤 조치가 가장 효과적인지 비교 분석을 통해 정리해 보았습니다. 아래 표를 참고하여 현재 상황에 맞는 해결책을 선택하시기 바랍니다.
| 락 발생 상황 | 핵심 증상 | 지연 허용 시간 | ✅ 추천 해결책 (우선순위) | ⚠️ 시급성 |
|---|---|---|---|---|
| Full Load 후 CDC 전환 시 스냅샷 락 | 전체 쓰기 정지, 스로틀링 | 30분 ~ 1시간 가능 | 태스크 생성 시 Transaction Consistency를 Disabled로 변경하고, ParallelLoadThreads를 1~2로 낮춰 재실행 |
높음 (서비스 지연 중) |
| 바이너리 로그 포지션 역행 | 복제 Lag 증가, 디스크 I/O 폭주 | 1시간 ~ 수시간 가능 | 태스크 재개 시 Resume from last stop position이 아닌 새 태스크로 Use timestamp를 현재 시각으로 정확히 설정 |
중간 |
| 인덱스 미스로 인한 Gap Lock (특정 쿼리만 대기) |
특정 테이블 INSERT/UPDATE 지연 | 10분 ~ 30분 가능 | 소스 테이블에 DMS 캡처 조건에 맞는 복합 인덱스 추가 (예: PK + Updated_at) 및 binlog_row_image=FULL 확인 |
중간 |
위 표의 해결책을 적용하기 전에 현재 DB 부하와 DMS 태스크 상태를 함께 확인하는 것을 권장합니다. 락의 원인이 뚜렷하지 않다면 태스크를 먼저 중지하고, CloudWatch 지표를 분석한 뒤 조치하세요.
4. DB 락 해결을 위한 실전 액션 플랜 (단계별 가이드)
문제의 원인을 파악했다면 이제 신속하게 조치해야 합니다. 단순히 DMS 태스크를 재시작하는 것만으로는 해결되지 않습니다. 아래의 단계별 가이드를 따라 진행해 보세요.
4.1. 1단계: DMS 태스크 중지 및 파라미터 즉시 수정
가장 먼저 DMS 콘솔로 이동하여 락을 유발한 태스크를 중지(STOP)합니다. 그리고 태스크 설정(Task Settings)의 JSON 편집기에서 아래 두 가지 파라미터를 수정합니다.
- FullLoadTransactionConsistencyTimeout: 이 값을 기본값(600초)보다 낮춥니다. 예를 들어 30초(30)로 설정하면 스냅샷 생성 대기 시간이 줄어듭니다. 너무 낮추면 Full Load 중 일관성 문제가 발생할 수 있으니 운영 환경에 맞게 조절하세요.
- ParallelLoadThreads: 이 값을 1로 설정합니다. 테이블 로딩을 동시에 처리하지 않고 순차적으로 처리하게 되어 락이 확장되는 것을 방지합니다.
- ParallelApplyThreads: CDC 적용 단계의 스레드 수입니다. 이 값도 1로 내려서 소스 DB의 락 경합을 최소화합니다.
주의: JSON 편집기에서 수정한 파라미터는 태스크 저장 후 재시작할 때 적용됩니다. 파라미터명이 정확하지 않으면 태스크 시작 시 오류가 발생할 수 있으니 복사/붙여넣기를 권장합니다.
4.2. 2단계: 소스 DB 세션 킬 및 락 확인
DMS 태스크가 중지되었음에도 불구하고 DB에 세션이 남아있을 수 있습니다. RDS 콘솔의 프로세스 리스트에서 DMS가 사용하는 사용자(예: dms_user)의 세션 중 State가 Waiting for table metadata lock 또는 Locked인 것을 발견하면 다음 명령으로 해당 프로세스를 종료합니다.
CALL mysql.rds_kill(thread_id);
4.3. 3단계: 태스크 재생성 및 CDC 시작 위치 조정
파라미터 수정 후 기존 태스크를 재개하는 것보다는 새로운 태스크를 생성하는 것을 강력히 권장합니다. 이 때 마이그레이션 유형은 “Migrate existing data and replicate ongoing changes”를 선택하고, 시작 시점은 “Start on a schedule”을 선택한 후 현재 시간을 지정합니다. 특히, “CDC start position” 부분에서 아래와 같이 설정합니다.
- Use timestamp: YES
- Start timestamp: 현재 UTC 시간 + 5분 (여유를 두어 락이나 지연으로 인한 시간 오차를 방지)
4.4. 4단계: 태스크 재시작 후 모니터링 강화
재기동 후에는 CloudWatch에서 DMS의 CDCLatencySource, CDCLatencyTarget, 그리고 소스 DB의 CPUUtilization과 DatabaseConnections를 함께 모니터링하세요. 복제 지연이 계속 증가한다면 태스크를 다시 중지하고 소스 테이블의 인덱스를 점검해야 합니다.
5. 잊지 말아야 할 DMS CDC 운영 팁 (락 예방을 위한 사전 체크리스트)
락이 발생한 후 해결하는 것도 중요하지만, 애초에 락이 발생하지 않도록 예방하는 것이 최선입니다. DMS CDC 연동을 시작하기 전에 아래 체크리스트를 반드시 확인하세요.
- 소스 DB 파라미터 그룹 수정:
binlog_format을ROW로,binlog_row_image를FULL로 설정해야 합니다.MINIMAL로 되어 있으면 필요한 이전 이미지가 없어 DMS가 추가 조회(쿼리)를 날리고, 이로 인해 락이 발생할 수 있습니다. - 타깃 테이블 비우기: 재시작 시 타깃 테이블에 기존 데이터가 있으면 DMS가 중복 데이터를 처리하면서 데드락(Deadlock)이 걸릴 수 있습니다. 신규 연동 시에는 타깃 테이블을 TRUNCATE 하고 시작하는 것이 안전합니다.
- 모니터링 지표 확인: CloudWatch에서 DMS 태스크의
CDCLatencySource(소스에서 캡처까지 지연)와CDCLatencyTarget(타깃 적용까지 지연)을 실시간으로 확인하세요. 이 값이 갑자기 증가하면 락이나 성능 저하의 신호입니다. - 바이너리 로그 보존 기간 확인: RDS 파라미터 그룹에서 binlog retention 시간을 확인하세요. DMS CDC가 중단된 시간이 로그 보존 기간을 넘으면 전체 재로드가 필요할 수 있습니다.
6. 결론: AWS DMS CDC 락, 준비된 자만이 피할 수 있다
AWS DMS CDC 연동은 단순한 복제 작업이 아니라 소스 DB의 트랜잭션과 깊이 상호작용하는 민감한 작업입니다. 이번 경험을 통해 DMS 태스크 설정 하나하나가 운영 DB의 안정성에 직결된다는 것을 뼈저리게 느꼈습니다. 특히 락이 걸렸을 때 당황하지 말고, 태스크를 중지한 후 위에서 소개한 “Transaction Consistency” 설정 해지와 바이너리 로그 시작 지점을 현재 시점으로 재조정하는 것이 가장 빠른 해결책이었습니다.
여러분은 저와 같은 실수를 반복하지 마시기 바랍니다. CDC 연동 전 반드시 소스 DB의 바이너리 로그 설정 기간(Retention)을 확인하고, 대용량 테이블은 사전에 인덱스를 최적화하세요. 그리고 항상 “설정은 신중하게, 적용은 순차적으로”라는 원칙을 지키시길 바랍니다. 이 글이 AWS DMS CDC를 준비하거나 운용 중인 모든 엔지니어분들의 소중한 시간을 아껴주는 지침이 되었기를 바랍니다. 운영 중인 DB에 락이 걸리는 최악의 상황, 이제는 충분히 예방할 수 있을 것입니다.