[Daily morning study] CDC (Change Data Capture) 개념과 활용
#daily morning study
CDC란 무엇인가
CDC(Change Data Capture)는 데이터베이스에서 발생하는 변경 사항(INSERT, UPDATE, DELETE)을 실시간으로 감지하고 캡처하는 기법이다. 원본 DB의 변경 이벤트를 다른 시스템(데이터 웨어하우스, 캐시, 검색 엔진, 메시지 큐 등)으로 전파하는 데 주로 사용한다.
전통적인 배치 방식(주기적 풀링)과의 가장 큰 차이는 지연시간(latency)이다. 배치는 분~시간 단위 지연이 생기지만, CDC는 밀리초~초 단위 수준의 거의 실시간 복제가 가능하다.
CDC의 주요 방식
1. 로그 기반 CDC (Log-based CDC)
가장 일반적으로 쓰이는 방식이다. 데이터베이스가 내부적으로 유지하는 트랜잭션 로그(WAL, binlog, redo log)를 읽어 변경 사항을 추출한다.
| DB | 로그 이름 |
|---|---|
| PostgreSQL | WAL (Write-Ahead Log) |
| MySQL | binlog (Binary Log) |
| Oracle | Redo Log |
| MongoDB | Oplog |
장점
- 원본 DB 성능에 거의 영향 없음 (로그는 어차피 생성됨)
- 트랜잭션 순서 보장
- DELETE 이벤트도 캡처 가능
단점
- DB별로 로그 포맷이 다름 → 구현 복잡도 증가
- 로그 보존 기간 설정 필요 (로그가 지워지면 복구 불가)
2. 트리거 기반 CDC (Trigger-based CDC)
DB 트리거를 이용해 변경 발생 시 별도의 이력 테이블에 레코드를 기록하는 방식이다.
CREATE TABLE orders_cdc (
id SERIAL PRIMARY KEY,
operation CHAR(1), -- 'I', 'U', 'D'
changed_at TIMESTAMP DEFAULT NOW(),
old_data JSONB,
new_data JSONB
);
CREATE OR REPLACE FUNCTION capture_orders_changes()
RETURNS TRIGGER AS $$
BEGIN
IF TG_OP = 'DELETE' THEN
INSERT INTO orders_cdc(operation, old_data)
VALUES ('D', row_to_json(OLD));
ELSIF TG_OP = 'INSERT' THEN
INSERT INTO orders_cdc(operation, new_data)
VALUES ('I', row_to_json(NEW));
ELSE
INSERT INTO orders_cdc(operation, old_data, new_data)
VALUES ('U', row_to_json(OLD), row_to_json(NEW));
END IF;
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER orders_cdc_trigger
AFTER INSERT OR UPDATE OR DELETE ON orders
FOR EACH ROW EXECUTE FUNCTION capture_orders_changes();
장점
- DB 표준 기능만으로 구현 가능
- 특정 컬럼 변경만 필터링하기 쉬움
단점
- 모든 DML 작업마다 트리거가 실행 → 원본 DB 부하 증가
- 대량 배치 작업(bulk load) 시 심각한 성능 저하
- 이력 테이블 관리 비용 발생
3. 쿼리 기반 CDC (Query-based / Timestamp-based CDC)
변경 추적용 컬럼(updated_at, version 등)을 두고 주기적으로 쿼리해 변경 레코드를 찾는 방식이다.
-- 마지막 체크 이후 변경된 레코드 조회
SELECT *
FROM orders
WHERE updated_at > :last_checked_at
ORDER BY updated_at;
장점
- 구현이 단순
- 특별한 DB 권한 불필요
단점
- DELETE 이벤트 캡처 불가 (레코드가 사라지면 알 수 없음)
- 변경 감지에 최소 1 폴링 주기만큼 지연 발생
updated_at컬럼이 없거나 업데이트 안 되는 경우 누락 가능
CDC 주요 도구
Debezium
가장 널리 쓰이는 오픈소스 CDC 플랫폼이다. Kafka Connect 위에서 동작하며 다양한 DB 커넥터를 제공한다.
[PostgreSQL WAL]
↓
[Debezium PostgreSQL Connector]
↓
[Apache Kafka Topic]
↓
[Consumer (Elasticsearch, Redis, DW, etc.)]
PostgreSQL의 경우 논리적 복제(logical replication)를 활성화해야 한다.
-- postgresql.conf
wal_level = logical
-- 복제 슬롯 생성 (Debezium이 자동 생성하기도 함)
SELECT pg_create_logical_replication_slot('debezium_slot', 'pgoutput');
Debezium이 캡처하는 이벤트 메시지 예시:
{
"op": "u",
"before": {
"id": 101,
"status": "PENDING",
"amount": 5000
},
"after": {
"id": 101,
"status": "SHIPPED",
"amount": 5000
},
"source": {
"ts_ms": 1727654400000,
"db": "shop",
"table": "orders",
"lsn": 12345678
}
}
op 값: c(create), u(update), d(delete), r(read/snapshot)
AWS DMS (Database Migration Service)
AWS에서 제공하는 관리형 데이터 마이그레이션 및 CDC 서비스다. 지속적 복제(Continuous Replication) 모드로 운영하면 CDC처럼 사용할 수 있다.
[Source DB (RDS, on-premise)]
↓
[AWS DMS Replication Instance]
↓
[Target (S3, Kinesis, Redshift, etc.)]
CDC 활용 사례
1. 검색 엔진 동기화
DB 변경 사항을 Elasticsearch에 실시간 반영한다.
PostgreSQL → Debezium → Kafka → Kafka Connect ES Sink → Elasticsearch
DB가 원천(source of truth)이 되고, Elasticsearch는 검색 최적화된 복제본 역할을 한다.
2. 캐시 무효화 (Cache Invalidation)
DB 레코드가 변경될 때 Redis 캐시를 자동으로 삭제하거나 갱신한다.
[Order UPDATE] → [CDC Event] → [Consumer]
↓
redis.del("order:101")
애플리케이션 코드에서 캐시 갱신 로직을 분리할 수 있어 코드가 단순해진다.
3. 이벤트 소싱 / 감사 로그
모든 데이터 변경 이력을 별도 저장소에 영구 보관한다. 금융, 의료 등 규제가 엄격한 도메인에서 감사 목적으로 많이 쓰인다.
4. 데이터 웨어하우스 적재
운영 DB에서 발생한 변경을 실시간으로 DW(Redshift, BigQuery, Snowflake)에 적재해 분석 지연을 줄인다.
CDC 설계 시 주의점
스키마 변경 처리
원본 테이블에 컬럼이 추가/삭제되면 CDC 파이프라인이 깨질 수 있다. Debezium은 스키마 레지스트리(Confluent Schema Registry 등)와 연동해 이 문제를 관리한다.
초기 스냅샷 (Initial Snapshot)
CDC를 처음 구성할 때는 기존 데이터를 한 번 전체 복사(snapshot)한 뒤 이후 변경 이벤트를 이어받아야 한다. Debezium은 snapshot.mode 설정으로 이를 제어한다.
이벤트 중복 처리 (At-least-once)
CDC 시스템은 일반적으로 at-least-once 전달을 보장한다. 컨슈머가 멱등하게 처리(upsert 등)하도록 설계해야 한다.
복제 슬롯 관리 (PostgreSQL)
PostgreSQL의 논리 복제 슬롯은 소비되지 않은 WAL을 보관하므로, 컨슈머가 오래 멈추면 디스크가 차버릴 수 있다. 모니터링과 슬롯 삭제 정책이 필요하다.
-- 복제 슬롯 상태 확인
SELECT slot_name, active, restart_lsn, confirmed_flush_lsn
FROM pg_replication_slots;
정리
| 방식 | 원본 부하 | DELETE 캡처 | 지연 | 복잡도 |
|---|---|---|---|---|
| 로그 기반 | 낮음 | 가능 | 매우 낮음 | 높음 |
| 트리거 기반 | 높음 | 가능 | 낮음 | 중간 |
| 쿼리 기반 | 중간 | 불가 | 폴링 주기 | 낮음 |
실시간 데이터 파이프라인이 필요하고 원본 DB 부하를 최소화하고 싶다면 로그 기반 CDC + Debezium + Kafka 조합이 사실상 표준이 되고 있다.