Kafka DLT Replay 전략 만들기

김기현·2024년 11월 17일
2

1. 서론

Kafka는 대규모 데이터 스트리밍을 처리하는 데 최적화된 분산 메시징 시스템이에요. 하지만 모든 메시지가 항상 성공적으로 처리되는 건 아니죠. 예를 들어, 데이터 포맷이 잘못되었거나 외부 서비스와의 통신 오류 등 다양한 이유로 메시지 처리에 실패할 수 있어요. 이런 실패한 메시지를 따로 관리하고 다시 처리할 수 있는 방법이 바로 Dead Letter Topic(DLT)입니다.

문제 정의

메시지 처리 중 오류가 발생하면 해당 메시지를 DLT로 보내 실패한 메시지를 별도로 관리하게 됩니다. 하지만 단순히 DLT에 메시지를 보낸 후에는 이 메시지를 어떻게 다시 처리할지 고민이 필요해요. 재처리 전략을 잘못 설계하면 시스템의 안정성이 떨어지거나 메시지 중복 처리 등의 문제가 발생할 수 있답니다. 그래서 오늘은 두 가지 DLT Replay 전략을 소개하고, 어떤 상황에서 어떤 전략이 더 적합한지 알아보려고 해요.

2. 본론 (해결 과정)

오늘은 두 가지 DLT Replay 전략을 살펴볼게요:

  1. DLT를 Retry Topic으로 Reproduce하는 전략
  2. Consumer Offset을 초기화하여 DLT 메시지를 재처리하는 전략

전략 1: DLT를 Retry Topic으로 Reproduce하는 전략

이 첫 번째 전략은 DLT에 저장된 메시지를 별도의 Retry Topic으로 전송하여 재처리하는 방법이에요. 이 방법의 가장 큰 장점은 기존의 메시지 처리 흐름을 방해하지 않고 실패한 메시지만 따로 처리할 수 있다는 점이에요.

구현 과정

  1. DLT에서 실패한 메시지를 읽어와서 Retry Topic으로 전송
    • DLT에 저장된 메시지를 Kafka AdminClient를 사용하여 읽어옵니다.
    • 읽어온 메시지를 Retry Topic으로 전송합니다.
  2. Retry Topic을 소비하는 별도의 Consumer를 만들어 재처리
    • Retry Topic을 구독하는 별도의 Consumer를 설정합니다.
    • 이 Consumer는 Retry Topic에서 메시지를 읽어와 다시 처리합니다.
    • 처리 중 다시 실패하면 DLT로 다시 전송하거나 최대 재시도 횟수를 초과하면 DLT로 이동시킵니다.

Kotlin Spring Pseudo 코드

import org.springframework.kafka.core.KafkaTemplate
import org.springframework.kafka.annotation.KafkaListener
import org.springframework.stereotype.Service
import org.apache.kafka.clients.consumer.ConsumerRecord

@Service
class DltReplayService(private val kafkaTemplate: KafkaTemplate<String, String>) {

    fun replayDltMessages(dltTopic: String, retryTopic: String) {
        val dltMessages = readMessagesFromTopic(dltTopic)
        dltMessages.forEach { message ->
            kafkaTemplate.send(retryTopic, message.key, message.value)
        }
    }

    private fun readMessagesFromTopic(topic: String): List<ConsumerRecord<String, String>> {
        // DLT에서 메시지 읽기 로직 구현
        // 예: KafkaConsumer를 사용하여 메시지 조회
        return listOf()
    }
}

@Service
class RetryConsumerService {

    @KafkaListener(topics = ["retry-topic"], groupId = "retry-group")
    fun listenRetryMessages(message: String) {
        try {
            // 메시지 처리 로직
        } catch (e: Exception) {
            // 실패 시 다시 DLT로 전송 또는 최대 재시도 횟수 초과 시 DLT로 이동
        }
    }
}

장점

  • 동시성 유지: 기존 Consumer의 흐름을 방해하지 않고 독립적으로 재처리 가능.
  • 유연성: Retry Topic에 대해 다양한 설정(재시도 횟수, 지연 시간 등)을 적용할 수 있음.
  • 안정성: Offset 초기화가 필요 없어서 시스템의 안정성을 유지할 수 있음.

단점

  • 추가 리소스 필요: Retry Topic을 관리하기 위한 추가 리소스와 설정이 필요.
  • 복잡성 증가: 메시지 전송 및 관리 로직이 추가되어 시스템 복잡성이 조금 늘어남.

전략 2: Consumer Offset을 초기화하여 DLT 메시지를 재처리하는 전략

두 번째 전략은 Consumer 그룹의 Offset을 DLT 메시지가 있는 위치로 재설정하여 메시지를 다시 처리하는 방법이에요. 이 방법은 비교적 단순하게 구현할 수 있지만, 몇 가지 단점도 존재해요.

구현 과정

  1. DLT에 저장된 메시지의 Offset 위치를 찾기
    • DLT에 저장된 메시지의 정확한 Offset을 파악합니다.
  2. Consumer의 Offset을 해당 위치로 재설정
    • Consumer 그룹의 Offset을 DLT 메시지가 있는 위치로 재설정합니다.
  3. 메시지를 다시 처리
    • Offset이 재설정된 위치부터 메시지를 다시 읽어와 처리합니다.

장점 및 단점

전략장점단점
DLT를 Retry Topic으로 Reproduce- Consumer 흐름 방해 없음
- 유연한 재시도 설정
- 안정성 유지
- 추가 리소스 필요
- 시스템 복잡성 증가
Consumer Offset 초기화- 단순한 구현
- 추가 리소스 불필요
- Consumer 중단 필요
- 데이터 중복 처리 위험
- 복구 시간 지연
  • 장점

    • 단순한 구현: 추가적인 Retry Topic 없이 Offset을 재설정하여 재처리 가능.
    • 적은 리소스 사용: 별도의 Retry Topic을 관리할 필요가 없어 리소스 절약.
  • 단점

    • Consumer 중단 필요: Offset 초기화를 위해 Consumer를 일시 중지해야 해서 시스템 가용성이 떨어질 수 있음.
    • 데이터 중복 처리 위험: Offset을 재설정하면 이미 처리된 메시지를 다시 처리할 가능성이 있어 데이터 중복이 발생할 수 있음.
    • 복구 시간 지연: Consumer를 재시작하는 과정에서 복구 시간이 지연될 수 있음.

3. 결론

오늘은 Kafka의 DLT Replay 전략에 대해 두 가지 접근법을 살펴보았어요. Retry Topic을 활용한 전략은 시스템의 가용성을 유지하면서 유연하게 재처리를 할 수 있는 장점이 있지만, 추가 리소스가 필요하고 시스템 복잡성이 조금 증가하는 단점이 있어요. 반면, Offset 초기화 전략은 구현이 단순하고 리소스를 절약할 수 있지만, Consumer를 일시 중지해야 하고 데이터 중복 처리의 위험이 있다는 단점이 있죠.

개인적으로는 대규모 시스템이나 높은 가용성이 요구되는 환경에서는 Retry Topic을 활용한 전략이 더 적합하다고 생각해요. 하지만 소규모 프로젝트나 단순한 요구사항을 가진 경우에는 Offset 초기화 전략도 충분히 유용할 수 있습니다. 여러분의 프로젝트에 맞는 전략을 선택해서 안정적이고 효율적인 Kafka 메시지 처리를 구현해보세요!

0개의 댓글