토픽 분리 vs 파티션 분할

둘은 같은 말이 아니다.

  • 토픽 분리: 토픽 자체를 여러 개로 나누는 것. 예: rides.raw, rides.processed, rides.dlq
  • 파티션 분할: 하나의 토픽 내부를 파티션으로 나누는 것. 예: Partition 0, 1, 2

목적도 다르다.

  • 토픽 분리: 의미와 운영 정책을 분리한다.
  • 파티션 분할: 처리량과 확장성을 확보한다.

토픽 자체를 분리하는 이유

  • 도메인/스키마 분리: 이벤트 성격이 다르면 데이터 계약을 독립적으로 관리할 수 있다.
  • 정책 분리: retention, ACL, 압축, 복제 정책을 토픽별로 다르게 설정할 수 있다.
  • 운영 분리: raw/processed/dlq 단위로 모니터링하고 장애 대응하기 쉽다.

파티션으로 나누는 이유

  • 병렬 처리: Consumer Group이 파티션을 나눠 읽어 처리량을 올린다.
  • 수평 확장: 트래픽이 커지면 파티션/컨슈머 인스턴스를 함께 늘릴 수 있다.
  • 순서 보장 범위 제어: 전체 토픽이 아니라 파티션 단위 순서를 보장한다.
  • 복구 단순화: 오프셋을 파티션별로 관리해 재처리 범위를 줄일 수 있다.

DLQ(Dead Letter Queue) 패턴

DLQ는 “정상 처리에서 탈락한 이벤트를 격리하는 안전 구역”이다.

가장 흔한 흐름은 아래와 같다.

  1. Producer가 이벤트를 raw 토픽에 적재한다.
  2. Consumer/Flink가 raw를 읽어 검증하고 변환한다.
  3. 성공 이벤트는 processed(또는 DB sink)로 보낸다.
  4. 실패 이벤트는 dlq로 보내고 실패 메타데이터를 남긴다.

요점은 Producer가 분류를 다 하는 것이 아니라, 보통 처리 계층(Consumer/Flink)이 판정하고 분기한다는 점이다.

DLQ를 두면 좋은 점

  • 본선 보호: 문제 이벤트가 있어도 정상 처리 흐름을 멈추지 않는다.
  • 원인 추적: 실패 사유를 근거로 스키마 불일치나 버그를 빠르게 찾을 수 있다.
  • 재처리 가능: 수정 후 DLQ 건만 선별해서 재주입할 수 있다.

운영 팁

DLQ 이벤트에는 최소한 아래 필드를 함께 남기는 것을 권장한다.

  • original_payload: 원본 메시지
  • error_reason: 실패 사유 요약
  • failed_at: 실패 시각
  • source_topic: 원본 토픽명
  • consumer_group: 실패를 기록한 처리 주체

선택적으로 stack_trace 또는 error_code를 넣으면 장애 분석 속도가 더 빨라진다.

한 줄 요약

  • 토픽 분리는 의미와 정책을 나누기 위한 것
  • 파티션 분할은 성능과 확장을 위한 것
  • DLQ는 실패 데이터를 격리하고, 서비스 안정성과 운영 효율을 높이는 패턴