1. Debezium란?
Debezium는 오픈소스 Change Data Capture (CDC) 플랫폼입니다. 데이터베이스의 트랜잭션 로그(예: MySQL의 binlog, PostgreSQL의 WAL)를 모니터링하여 데이터 변경 사항을 실시간으로 캡처하고, 이를 이벤트 스트림(주로 Apache Kafka)으로 전송하는 역할을 합니다.
마이크로서비스 아키텍처, 데이터 레이크/웨어하우스 적재, 캐시/검색엔진 동기화 등 실시간 데이터 파이프라인의 핵심 컴포넌트로 사용됩니다.
🔍 로그 기반 CDC
데이터베이스의 트랜잭션 로그를 직접 읽어 변경을 감지합니다. 트리거나 쿼리 폴링 방식에 비해 원본 DB 부하가 극히 적고, 모든 변경 사항을 정확히 포착할 수 있습니다.
⚡ 실시간 스트리밍
변경 이벤트를 거의 실시간으로 Kafka 토픽에 발행합니다. 이벤트는 JSON 또는 Avro 형식으로, 스키마 레지스트리와 연동 가능합니다.
🔗 커넥터 생태계
MySQL, PostgreSQL, MongoDB, SQL Server, Oracle, Cassandra 등 주요 DBMS용 커넥터를 제공합니다. Kafka Connect 프레임워크 위에서 동작해 확장성이 뛰어납니다.
2. 왜 써야 하는가?
기존 데이터 동기화 방식과 Debezium의 로그 기반 CDC를 비교합니다.
| 방식 | 원리 | 장점 | 단점 |
|---|---|---|---|
| 애플리케이션 이중 작성 | 비즈니스 로직에서 두 시스템에 각각 INSERT/UPDATE | 간단한 구현 | 데이터 불일치 위험高, 코드 복잡도 증가, 트랜잭션 보장 어려움 |
| 폴링 (Polling) | updated_at 컬럼을 주기적으로 SELECT | DB 종속성 낮음 | 실시간성 떨어짐, 변경 누락 가능성, 원본 DB 부하 증가 |
| 트리거 (Trigger) | DB 트리거로 변경 시 별도 테이블에 기록 | 모든 변경 캡처 가능 | 원본 DB 성능 저하, 유지보수 복잡, 확장성 낮음 |
| Debezium (로그 기반 CDC) | 트랜잭션 로그(binlog/WAL) 읽기 | 원본 DB 부하 극소, 실시간성, 정확한 변경 이력, 확장성 高 | DB 로그 포맷 이해 필요, 설정 복잡도, 추가 인프라(Kafka) 필요 |
💡 선택 가이드
Debezium를 선택해야 할 때: 마이크로서비스 간 데이터 동기화, 실시간 분석/대시보드, 데이터 레이크 적재, 캐시/검색엔진 동기화, 데이터 마이그레이션 모니터링 등 실시간성과 정확성이 모두 중요한 시나리오입니다.
3. 핵심 개념
Debezium는 Kafka Connect의 소스 커넥터(Source Connector)로 동작합니다. 아래는 전형적인 아키텍처입니다.
주요 컴포넌트
- 커넥터(Connector): 특정 DBMS용 플러그인 (예: debezium-connector-mysql).
- 태스크(Task): 커넥터의 실제 작업 인스턴스. 병렬 처리를 위해 여러 태스크 실행 가능.
- 오프셋(Offset): 커넥터가 읽은 로그의 위치를 저장하여 장애 복구 시 중단 지점부터 재개.
- 스키마 레지스트리(Schema Registry): 이벤트의 Avro 스키마를 중앙 관리 (Confluent Schema Registry와 연동).
📦 이벤트 구조
Kafka로 전송되는 각 메시지(이벤트)는 key와 value를 가집니다. key는 기본 키를, value는 변경 전/후 데이터와 메타데이터를 포함합니다.
4. 퀵스타트 (MySQL + Docker)
Docker Compose를 사용해 MySQL, Zookeeper, Kafka, Kafka Connect (Debezium)를 한 번에 실행합니다.
단계 1: docker-compose.yml 작성
version: '3.8'
services:
zookeeper:
image: confluentinc/cp-zookeeper:latest
environment:
ZOOKEEPER_CLIENT_PORT: 2181
ZOOKEEPER_TICK_TIME: 2000
kafka:
image: confluentinc/cp-kafka:latest
depends_on:
- zookeeper
environment:
KAFKA_BROKER_ID: 1
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: debezium
MYSQL_USER: debezium
MYSQL_PASSWORD: dbz
ports:
- "3306:3306"
command: --binlog-format=ROW --default-authentication-plugin=mysql_native_password
connect:
image: debezium/connect:latest
depends_on:
- kafka
- mysql
environment:
BOOTSTRAP_SERVERS: kafka:9092
GROUP_ID: 1
CONFIG_STORAGE_TOPIC: connect_configs
OFFSET_STORAGE_TOPIC: connect_offsets
STATUS_STORAGE_TOPIC: connect_statuses
ports:
- "8083:8083"
단계 2: 인프라 실행 및 커넥터 등록
아래 명령어를 터미널에서 실행합니다.
# 1. 인프라 실행 docker-compose up -d # 2. MySQL에 샘플 데이터베이스 및 테이블 생성 (다른 터미널에서) docker exec -it <mysql-container-id> mysql -u root -pdebezium
MySQL 클라이언트에서:
CREATE DATABASE inventory;
USE inventory;
CREATE TABLE customers (
id INT PRIMARY KEY AUTO_INCREMENT,
first_name VARCHAR(50),
last_name VARCHAR(50),
email VARCHAR(100)
);
INSERT INTO customers (first_name, last_name, email) VALUES
('John', 'Doe', 'john@example.com'),
('Jane', 'Smith', 'jane@example.com');
단계 3: Debezium MySQL 커넥터 등록
Kafka Connect REST API를 호출해 커넥터를 생성합니다.
curl -X POST http://localhost:8083/connectors \
-H "Content-Type: application/json" \
-d '{
"name": "inventory-connector",
"config": {
"connector.class": "io.debezium.connector.mysql.MySqlConnector",
"tasks.max": "1",
"database.hostname": "mysql",
"database.port": "3306",
"database.user": "root",
"database.password": "debezium",
"database.server.id": "184054",
"database.server.name": "dbserver1",
"database.include.list": "inventory",
"table.include.list": "inventory.customers",
"database.history.kafka.bootstrap.servers": "kafka:9092",
"database.history.kafka.topic": "dbhistory.inventory",
"include.schema.changes": "true"
}
}'
단계 4: 이벤트 소비 (Python 예제)
from kafka import KafkaConsumer
import json
consumer = KafkaConsumer(
'dbserver1.inventory.customers', # 토픽명: {server}.{database}.{table}
bootstrap_servers='localhost:9092',
auto_offset_reset='earliest',
value_deserializer=lambda m: json.loads(m.decode('utf-8'))
)
print("Listening for changes...")
for message in consumer:
event = message.value
op = event['op'] # 'c'=create, 'u'=update, 'd'=delete
source = event['source']
after = event.get('after', {})
print(f"Operation: {op} | Table: {source['table']} | Data: {after}")
⚠️ 주의사항
프로덕션 환경에서는 database.password를 안전하게 관리하고, SSL 설정, 적절한 tasks.max 및 토픽 복제 계수를 설정해야 합니다.
5. 핵심 설정 레퍼런스
MySQL 커넥터를 기준으로 한 필수 및 주요 설정 목록입니다.
| 설정 | 기본값 | 설명 |
|---|---|---|
connector.class |
- | 반드시 지정. io.debezium.connector.mysql.MySqlConnector |
database.hostname |
- | DB 서버 호스트명 |
database.user, database.password |
- | DB 접속 계정 (로그 읽기 권한 필요) |
database.server.name |
- | 논리적 서버명. Kafka 토픽명의 접두사로 사용됨 |
database.include.list |
모든 DB | 모니터링할 DB 화이트리스트 (쉼표 구분) |
table.include.list |
모든 테이블 | 모니터링할 테이블 화이트리스트 (예: inventory.customers) |
include.schema.changes |
true | DDL 변경(테이블 생성/수정) 이벤트도 캡처할지 여부 |
snapshot.mode |
initial | 초기 스냅샷 방식: initial(전체), when_needed, never |
decimal.handling.mode |
precise | DECIMAL 타입 처리: precise(문자열), double, string |
time.precision.mode |
adaptive | 시간 타입 정밀도: adaptive(마이크로초), connect(밀리초) |
tombstones.on.delete |
true | 삭제 이벤트 시 null 값의 토큰스톤 메시지 발행 여부 (로그 압축용) |
6. 실무 팁 & 트러블슈팅
자주 겪는 문제
🚫 커넥터 시작 실패
증상: 커넥터 상태가 FAILED, 로그에 "binlog 접근 불가" 오류.
해결:
- MySQL의
binlog_format=ROW확인. - DB 사용자에게
REPLICATION SLAVE, REPLICATION CLIENT권한 부여. - 호스트명/포트 방화벽 확인.
🐌 이벤트 지연 (Lag)
증상: Kafka 메시지 생산은 되지만 실시간성이 떨어짐.
해결:
tasks.max증가 (테이블이 많을 경우).- Kafka 브로커 및 네트워크 성능 점검.
- 커넥터 배치 사이즈 조정 (
max.batch.size).
📈 스키마 변경 대응
증상: ALTER TABLE 후 컨슈머에서 필드 누락 또는 파싱 오류.
해결:
include.schema.changes=true로 DDL 이벤트 수신.- Avro + Schema Registry 사용 시 호환성 모드 설정.
- 컨슈머가 스키마 변경에 유연한 라이브러리 사용 (예: Apache Spark).
성능 튜닝 팁
- 병렬 처리: 파티션 키를 명시적으로 설정하거나
tasks.max를 늘려 여러 테이블을 병렬로 처리. - 스냅샷 최적화: 대용량 테이블의 초기 스냅샷 시
snapshot.mode=initial_only후 증분 모드로 전환 고려. - 모니터링: JMX 메트릭 (예:
MaxQueueSize,MilliSecondsBehindSource)을 Grafana 대시보드로 시각화. - 오프셋 관리: 정기적으로 오프셋 토픽의 로그 압축 상태를 확인하고, 커넥터 재시작 시 오프셋 초기화에 주의.
🔧 유용한 진단 명령어
# 커넥터 상태 확인 curl -s http://localhost:8083/connectors/inventory-connector/status | jq . # 커넥터 설정 조회 curl -s http://localhost:8083/connectors/inventory-connector | jq . # Kafka 토픽 메시지 확인 (최근 5개) docker exec <kafka-container> kafka-console-consumer \ --bootstrap-server localhost:9092 \ --topic dbserver1.inventory.customers \ --from-beginning --max-messages 5
7. 참고 자료
- 📘 Debezium 공식 문서 - 가장 상세하고 최신의 정보원
- 🧪 Debezium 예제 저장소 - 다양한 DB와 시나리오별 샘플 코드
- 🔗 Kafka KIPs - Kafka의 변화와 최신 기능 이해
- ✍️ Confluent 블로그 - CDC와 스트리밍 데이터 파이프라인 실무 사례
- 추천 도서: "Kafka: The Definitive Guide" (CDC와 Debezium 관련 장 포함)