최근 진행한 PDF 변환 프로젝트에서 적용한 CDC 를 통해 견고한 Event-Driven-Architecture 를 구성한 경험을 리뷰하고자 한다.
기존의 메시징 비동기처리를 통한 데이터 흐름은 이러했다.

- 사용자의 변환 요청
- WAS 서버는 내부 비즈니스 로직을 통해 파일정보 파싱 및 데이터베이스 저장
- HTTP Polling Scheduling 으로 요청 테이블 스캔
- 파일정보 바인딩하여 메시지 브로커에게 퍼블리싱

Debezium 을 별도의 독립 서버로 띄우기로 했다.

docker-compose.yml
services:
debezium:
image: quay.io/debezium/server:3.4
container_name: event-server
volumes:
- ./debezium/config:/debezium/config
- ./debezium/data:/debezium/data
env_file:
- ./debezium/config/application-local.properties
application.properties
# ---내보낼 플랫폼를 지정 (rmq)---
debezium.sink.type=rabbitmq
# ---RabbitMQ 설정---
debezium.sink.rabbitmq.connection.host=${RABBITMQ_HOST}
debezium.sink.rabbitmq.connection.port=5672
debezium.sink.rabbitmq.connection.username=${RABBITMQ_USERNAME}
debezium.sink.rabbitmq.connection.password=${RABBITMQ_PASSWORD}
debezium.sink.rabbitmq.exchange=${RABBITMQ_EXCHANGE}
debezium.sink.rabbitmq.routingKey=${RABBITMQ_ROUTINGKEY}
# ---DB 설정---
debezium.source.connector.class=io.debezium.connector.mysql.MySqlConnector
debezium.source.database.hostname=${DB_HOST}
debezium.source.database.port=3306
debezium.source.database.user=${DB_USERNAME}
debezium.source.database.password=${DB_PASSWORD}
debezium.source.database.connectionTimeZone=Asia/Seoul
debezium.source.database.server.id=15551
debezium.source.topic.prefix=cdc.event
debezium.source.database.include.list=api
debezium.source.table.include.list=api.outbox_event
# ---데이터 변환 설정---
# Key 를 JSON 포맷으로 변환
debezium.source.key.converter=org.apache.kafka.connect.json.JsonConverter
# 메시지 용량 최적화를 통해 스키마 정보 제거1
debezium.source.key.converter.schemas.enable=false
# Value 를 JSON 포맷으로 변경
debezium.source.value.converter=org.apache.kafka.connect.json.JsonConverter
# 메시지 용량 최적화를 통해 스키마 정보 제거2
debezium.source.value.converter.schemas.enable=false
# ---offset 및 스키마 히스토리 설정---
# Binlog 를 어디까지 읽었는지(offset) 기록할 파일 경로 지정
debezium.source.offset.storage.file.filename=data/offsets.dat
# offset 을 파일에 얼마나 자주 저장할지 주기 설정 (10초)
debezium.source.offset.flush.interval.ms=10000
# 테이블 변경 이력을 기록할 저장소 타입 지정(파일 시스템 사용)
debezium.source.schema.history.internal=io.debezium.storage.file.history.FileSchemaHistory
# 테이블 변경 이력 저장 경로 지정
debezium.source.schema.history.internal.file.filename=data/schemahistory.dat
별도의 Transaction Outbox 패턴을 적용했으므로,
감지 대상 테이블인 outbox_event 에서는 Insert 또는 주기적인 배치 Delete 만 진행할 예정이므로
특정 operation 에만 동작하도록 설정하진 않았다.
또한 yml 파일은 지원하지않으므로 가급적 properties 형식으로 작성해야한다.

- 사용자의 변환 요청
- WAS 서버는 내부 비즈니스 로직을 통해 파일정보 파싱 및 history 요청 데이터, outbox 에 payload(사용자 요청 메타데이터) 테이블에 저장
- Debezium 이 outbox 테이블의 insert log 를 감지하고 메시지 브로커에게 payload 를 전송
이 경우 스프링 컨테이너에 RabbitAdmin 을 빈으로 등록해줘야한다.

RabbitMQ Admin Tracing 에서 Debezium 이 전달한 메시지를 확인해보았다.

문제 항목: Routing keys: [<<>>]
Debezium 이 RabbitMQ 에서 설정한 RoutingKey 를 찾지못하는 것 같았다.



문제 원인은 Debezium 내부의 변환 필터나 속성명이 카멜 케이스 형식을 기반으로 라우팅 키를 자동 생성하거나 매핑하기 때문이었다. 최근 Debezium Server의 버전이 올라가면서 설정 사양이 하이픈을 사용하는 케밥 케이스에서 카멜 케이스로 표준화되었다고 한다.
위 내용을 적용하면서 내가 설정한 "cdc.event.message" 라는 라우팅 키가 성공적으로 바인딩된 것을 확인할 수 있었다.