AWS DMS CDC 연동 중 DB 락(Rock) 발생 원인과 3가지 실전 해결법

서론: 난데없이 걸려버린 DB 락(Lock), 그리고 멈춰버린 하루

운영 중인 서비스의 DB를 AWS DMS(Data Migration Service)로 CDC(Change Data Capture) 연동하는 작업은 사전 검토가 무엇보다 중요합니다. 실제로 실시간 동기화를 목표로 DMS 태스크를 실행했는데, 정작 CDC 태스크가 실행된 지 몇 분 만에 운영 테이블에 락(Lock)이 걸려버리는 경험을 하게 되면 업무 전체가 마비되곤 합니다.

예를 들어 수만 건 이상의 레코드를 가진 대용량 테이블을 대상으로 DMS CDC 최초 로드(Full Load + CDC)를 실행하면, 수 초 만에 해당 테이블에 대한 모든 Insert/Update가 블로킹(Blocking)되는 대형 사고가 발생할 수 있습니다. 서비스 장애로 이어지기 전에 이 글에서는 AWS DMS CDC 연동 중 발생하는 DB 락의 근본 원인과 다양한 상황에서 적용 가능한 3가지 실전 해결법을 상세히 공유합니다.

📌 글의 핵심 요약 (3줄 요약)
– AWS DMS CDC 최초 로드 시, 대상 테이블 전체에 ACCESS EXCLUSIVE 락이 걸리기보다는 대량 데이터 적재와 인덱스 갱신 과정에서 발생하는 행(Row) 락 과다 경합이 실제 장애의 주범인 경우가 많습니다.
– 해결책은 3가지: ① DMS 태스크 설정에서 Parallel Load / Multi-thread를 조정하거나, ② 원본에서 CDC 시작 지점(LSN)을 오프셋하여 피크타임과 겹치지 않게 하거나, ③ 테이블 매핑 시 필터 조건을 활용해 초기 로드 데이터 범위를 줄이는 것입니다.
가장 확실한 실전 팁: 운영 시간에는 DMS를 Full Load + CDC 모드로 통합 실행하지 말고, 스냅샷(Snapshot)만 떠서 적재한 후 CDC를 별도 모드로 전환하는 것을 강력히 권장합니다.

왜 AWS DMS CDC 연동에서 DB 락이 발생하는가?

DMS는 기본적으로 소스 데이터베이스에서 트랜잭션 로그를 읽어(예: PostgreSQL의 WAL, MySQL의 binlog) 대상으로 전달합니다. 이때 초기 스냅샷(Full Load) 단계에서 모든 데이터를 읽어 대상 테이블에 INSERT하게 되는데, 이 과정에서 락이 발생하는 주요 지점은 다음과 같습니다.

– DMS는 대상 테이블에 대량 INSERT를 수행하기 전에, 일관성 있는 스냅샷을 위해 소스 테이블에 짧은 시간 동안 짧은 락(MVCC 모델이 아닐 경우 접근 제한)을 획득하려 시도합니다.
– 이후 대상 테이블에 기록하는 동안, 소스 테이블에서 DMS가 읽은 트랜잭션 로그와 실제 데이터 변경이 동시다발적으로 발생하면 DMS 내부 캐시와 소스의 락 대기가 발생합니다.
하지만 진짜 주범은 보통 ‘대량 INSERT로 인한 인덱스 페이지 분할(Page Split)’과 ‘락 에스컬레이션(Row Lock → Table Lock)’입니다. 특히 PostgreSQL과 같은 DB에서는 DMS가 `session_replication_role = replica`로 동작할 때 FK 제약조건을 무시하지 못해, 외래키 무결성 검사 시점에 전체 테이블 락이 잠깐 발생할 수 있습니다.

락(Lock) 단계별 증상 파악: 내 상황은 어디에 해당하나?

막연히 ‘락이 걸렸다’고 하기엔, 실제 운영 상황에서의 증상은 저마다 다릅니다. 아래 비교 분석 표를 통해 내가 마주한 상황이 어떤 유형인지 먼저 진단해보세요.

락 증상 발생 주체 타임라인 해결 난이도 주로 발생하는 DB
타임아웃(Timeout) 에러 DMS 읽기/쓰기 Full Load 시작 직후 낮음 SQL Server / Oracle
대량 UPDATE 성능 저하 운영 애플리케이션 Full Load + CDC 동시 진행 시 중간 MySQL / MariaDB
전체 테이블 블로킹 (Locked) DMS 트랜잭션 인덱스 생성/재구성 시점 높음 PostgreSQL
CPU는 낮은데 대기 시간만 증가 OCI / 디스크 I/O CDC 캡처 중 중간 전체

이 표에서 볼 수 있듯이, 단순히 락이 걸렸다고 동일한 해결책을 적용해서는 안 됩니다. 내가 처한 DB 종류와 락의 양상(타임아웃 vs 성능 저하 vs 단순 블로킹)에 따라 적용할 솔루션이 완전히 달라집니다.

3가지 실전 해결법: 상황별 맞춤 처방

🔧 해결법 1: DMS Task 설정을 병렬 로드(Parallel Load)로 튜닝하라

가장 흔하고 효과적인 첫 번째 방법은 DMS 태스크의 테이블 매핑(Target Table Settings)에서 ‘Parallel load’ 옵션을 활성화하고, MaxFullLoadSubTasks 및 ParallelLoadThreads 값을 조정하는 것입니다. 기본적으로 DMS는 8개의 스레드가 동시에 데이터를 적재하지만, 이 값을 무작정 늘리면 대상 테이블에 동시에 접근하는 세션이 늘어나 오히려 락 충돌이 심해질 수 있습니다.

실질적인 팁: 운영 환경에서 소스 DB가 PostgreSQL 또는 MySQL이라면 ParallelLoadThreads를 서버 코어 수의 1/2 정도로 낮춰서 테스트해보십시오. 스레드 수를 늘리는 것보다, 소스 DB의 쓰기 부하와 DMS의 읽기 부하 사이의 밸런스를 맞추는 것이 중요합니다. 예를 들어 8코어 서버라면 4개로 설정하고, 모니터링을 통해 락 대기가 줄어드는지 확인하는 방식입니다.

🔧 해결법 2: CDC 모드를 분리하고 LSN(Log Sequence Number) 오프셋을 활용하라

첫 번째 방법이 효과가 없거나, 이미 Full Load가 끝났는데 CDC 단계에서 지속적으로 락이 걸리는 경우가 있습니다. 이때는 DMS 태스크를 삭제하고, ‘Full Load Only’ 모드로 1차 적재를 완료합니다. 그 이후에 ‘CDC Only’ 모드로 새 태스크를 생성하고, 시작 지점(LSN, 또는 MySQL의 binlog 파일/위치)을 현재 시점보다 약간 뒤로 설정해줍니다.

이렇게 하면 DMS가 변경분만 추적하면서 시작되므로, 대량 스캔(Full Scan)과 인덱스 재구성으로 인한 락 경합 자체가 사라집니다. 이 방법은 특히 초기 로드 이후에도 데이터 변경이 매우 잦은 대용량 테이블에 필수적인 처방입니다. 다만, 시작 지점을 너무 과거로 설정하면 오히려 오래된 트랜잭션 문제가 발생할 수 있으니, 현재 시점에서 10~20분 이내의 오프셋을 권장합니다.

🔧 해결법 3: 테이블 매핑 필터링으로 초기 데이터 범위를 축소하라

만약 대상 테이블(수천만 건)을 모두 마이그레이션하기 부담스럽고, 최근 데이터만 실시간으로 필요하다면 DMS의 Table Mapping 규칙에 ‘Selection Rule’과 ‘Filter’ 조건을 추가하여 초기 로드 데이터 양을 줄일 수 있습니다. 예를 들어 created_at >= NOW() - INTERVAL '3' DAY 같은 필터를 걸면, 초기 풀로드 시 읽어야 할 레코드 수가 급감하면서 소스 테이블에 거는 스냅샷 락 시간이 비약적으로 단축됩니다.

이 방법은 전체 데이터 이관이 목적이 아닌 ‘최근 이벤트성 데이터만 실시간 복제하라’는 요구사항에 아주 잘 들어맞습니다. 필터를 추가하더라도 CDC 단계에서는 정상적으로 모든 변경 데이터가 수집됩니다. 단, 필터 조건으로 제외된 과거 데이터는 이후 필요할 때 개별적으로 이관하는 별도 계획을 세워두는 것이 좋습니다.

가장 확실한 실전 전략: 단계적 이행(Staged Migration)

위의 세 가지 해결법을 개별적으로 적용해도 좋지만, 가장 중요한 원칙은 운영 중인 서비스라면 ‘Full Load + CDC’를 통합 실행하지 않는 것입니다. 아래 3단계 시나리오를 권장합니다.

단계 작업 내용 기대 효과
1단계 (준비) 소스 DB 파라미터 그룹 튜닝 및 DMS 인스턴스 크기 검토 락 경합 최소화
2단계 (전환) DMS ‘Full Load Only’로 기초 데이터 적재 완료 장기간 락 없이 완료
3단계 (동기화) ‘CDC Only’ 태스크 신규 생성하여 실시간 반영 시작 트랜잭션 대기 없이 실시간 동기화 달성

이렇게 하면 DMS가 처음부터 대량 데이터를 읽기 위해 소스에 부하를 주는 시간대에, 운영 애플리케이션의 쿼리들이 기다리면서 발생하는 락 대기 현상을 원천적으로 차단할 수 있습니다.

권장 사항: 락이 걸렸을 때 지금 당장 취할 행동

이미 락이 걸려 서비스가 마비된 상황이라면 DMS 태스크를 즉시 중지(Stop)하는 것을 망설이지 마십시오. 이후 아래 순서를 따르세요.

1) pg_stat_activity / information_schema.innodb_trx 조회하여 현재 락을 잡고 있는 세션(PID)을 확인합니다.
2) 해당 세션의 상태가 ‘idle in transaction’ 상태로 남아 있다면 DMS가 트랜잭션을 커밋하지 못하고 오래 머물고 있는 것이므로 DMS 태스크를 재부팅(Resume) 하거나, 가능하다면 해당 세션을 Kill 합니다.
3) DMS 콘솔에서 태스크의 ‘Recovery’ 기능을 활성화하여 태스크가 중단된 시점부터 자동으로 로그를 재생성하게끔 설정합니다. (단, 오래된 트랜잭션으로 인해 추가 락이 발생할 수 있으니 태스크 실행 전에 반드시 커밋 대기 시간을 확인해야 합니다.)

결론: 삽질은 이쯤에서 끝내자

AWS DMS CDC 연동 시 락은 피할 수 없는 관문처럼 여겨지지만, 사실 대부분은 사전 설정(태스크 분리, 스레드 수 조절, 필터 조건)으로 충분히 회피 가능한 문제입니다. 수시간의 삽질 끝에 알게 된 것은, DMS 툴의 옵션이 많다고 해서 무조건 좋은 것이 아니라 ‘내 데이터 워크로드에 맞는 적절한 설정’이 가장 중요하다는 점입니다.

지금 당장 AWS 콘솔에서 DMS 태스크를 열어보십시오. 만약 단일 태스크로 Full Load와 CDC를 동시에 진행 중이라면 이 글에서 소개한 3가지 해결법(병렬 처리 튜닝, 태스크 분리, 필터 조건)을 하나씩 테스트해보시기를 권장합니다. 특히 데이터 양이 수십만 건 이상을 넘어서는 순간부터는 반드시 태스크 분리를 습관화하세요. 그러면 실시간 마이그레이션에서 더 이상 락 때문에 업무가 멈추는 일이 없을 것입니다.

Similar Posts

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다