Full Load와 CDC 접속점: 한 건도 빠뜨리거나 두 번 반영하지 않기
왜 초기 이관과 실시간 동기화를 함께 보아야 하나
CDC(Change Data Capture)는 운영 DB에서 새로 바뀐 행만 읽어 옮기는 방식이다. 그러나 새 대상에는 기존 데이터가 없다. 그래서 먼저 전체 데이터를 한 번 옮기는 Full Load가 필요하다.
진짜 어려운 부분은 두 작업 사이다. Full Load 동안에도 원본 DB는 계속 바뀐다. 어느 시점까지를 Full Load가 담고, 어느 시점부터 CDC가 책임질지를 명확히 해야 누락과 중복을 막을 수 있다.
리멤버가 AWS와 공개한 구조는 Aurora MySQL의 변경을 Debezium으로 읽고, Amazon MSK(Kafka)를 거쳐 Iceberg 기반 S3 Tables에 반영한다. 기존 데이터는 별도 복제본에서 AWS Glue PySpark로 Full Load했다.
1. 기준점을 먼저 잡는다
MySQL binlog은 커밋된 변경을 순서대로 남긴다. Debezium은 binlog의 위치를 기억하고 INSERT, UPDATE, DELETE 이벤트를 Kafka topic으로 내보낸다. 초기 스냅샷을 직접 생성할 때도 스냅샷이 보는 시점과 binlog 시작 위치를 쌍으로 보존해야 한다.
공개 사례에서는 Full Load를 위한 전용 Aurora replica를 만들어 운영 DB 부하를 분리했다. 복제본의 binlog 위치는 이후 CDC가 이어받을 기준점이 된다.
2. 먼저 받은 CDC를 버리지 않는다
새 테이블을 CDC 대상에 추가한 뒤 Full Load하면, Full Load 동안의 변경이 먼저 Kafka에 쌓일 수 있다. 이는 실패가 아니다. sink가 primary key 기준 upsert를 보장한다면 Full Load 후 그 이후 변경이 다시 적용되어 최종 상태로 수렴한다.
다만 upsert가 있다고 모든 문제가 풀리지는 않는다.
- PK가 없거나 중간에 바뀐 테이블은 별도 전략이 필요하다.
- delete와 tombstone을 sink가 어떻게 해석하는지 확인해야 한다.
- 스키마 변경 이력 topic을 분할하면 순서가 깨질 수 있다.
- sink commit 주기가 길면 freshness는 나빠지지만 작은 파일은 줄어든다.
3. Kafka Connect는 ‘운영할 서버’다
Source Connector는 MySQL의 변경을 topic으로 만들고, Sink Connector는 topic의 이벤트를 S3 Tables에 쓴다. 커넥터 설정 파일 하나로 끝나는 것이 아니다.
운영자는 다음을 보아야 한다.
- source의 binlog 위치와 Kafka offset
- connector·task 상태, restart 횟수, 에러된 레코드
- topic별 lag과 sink commit 주기
- 스키마 변경 실패와 대상 테이블 누락
- 중복 이벤트를 결과 상태로 수렴시키는 PK·upsert 규칙
리멤버의 공개 글은 초기에 MSK Connect를 사용했지만, 커넥터를 일시 중단·재시작하는 운영 제약 때문에 ECS 직접 배포로 전환했다고 설명한다. 기술 선택은 기능 목록보다 중단·재개·증설·복구 절차와 함께 평가해야 한다는 예다.
4. 전환 완료는 ‘파이프라인이 돌아감’이 아니다
신뢰할 수 있는 전환은 다음 근거를 남긴다.
- 소스와 타깃의 PK 집합이 같은가?
- 행 수뿐 아니라 핵심 속성의 hash·표본이 같은가?
- delete가 정책대로 반영됐는가?
- CDC lag가 0 또는 합의한 기준 이하인가?
- 재시작해도 동일한 최종 상태로 수렴하는가?
- 되돌릴 때 어느 binlog 위치와 스냅샷을 쓸지 알 수 있는가?