인프런 커뮤니티 질문&답변
kafka 실패 후 재시도 DLT 소비 무한으로 하는 현상이 발생합니다
작성
·
12
0
현상:
아래에도 동일하게 이슈 올려주신 분이 있는 것으로 보이는데 postman으로 다음과 같이 요청하였을 때, kafka에서 DLT 소비하는 과정에서 무한 반복하는 현상이 발생하면서 DLT 토픽 자체에 계속 쌓이게 됩니다!
@RetryableTopic에 autoStartDltHandler = False 설정을 해주거나, @DLTHandler를 정의 해줘야 DLT 소비를 무한으로 하지 않는 것 같은데 뭔가 설정이 잘못 된게 있을까요? ㅠ
요청 파라미터:
{
"from": "sender@naver.com",
"to": "fail@naver.com",
"subject": "heyyyy",
"body": "helloo"
}2026-02-01T15:53:25.480+09:00 ERROR 15124 --- [email-send-consumer] [ner#0.dlt-0-C-1] k.r.DeadLetterPublishingRecovererFactory : Record: topic = email.send.dlt, partition = 0, offset = 605, main topic = email.send threw an error at topic email.send.dlt and won't be retried. Sending to DLT with name email.send.dlt.
org.springframework.kafka.listener.ListenerExecutionFailedException: Listener failed
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.decorateException(KafkaMessageListenerContainer.java:3014) ~[spring-kafka-4.0.2.jar:4.0.2]
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeOnMessage(KafkaMessageListenerContainer.java:2914) ~[spring-kafka-4.0.2.jar:4.0.2]
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeOnMessage(KafkaMessageListenerContainer.java:2880) ~[spring-kafka-4.0.2.jar:4.0.2]
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeRecordListener(KafkaMessageListenerContainer.java:2790) ~[spring-kafka-4.0.2.jar:4.0.2]
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeWithRecords(KafkaMessageListenerContainer.java:2632) ~[spring-kafka-4.0.2.jar:4.0.2]
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeRecordListener(KafkaMessageListenerContainer.java:2526) ~[spring-kafka-4.0.2.jar:4.0.2]
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeListener(KafkaMessageListenerContainer.java:2164) ~[spring-kafka-4.0.2.jar:4.0.2]
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeIfHaveRecords(KafkaMessageListenerContainer.java:1541) ~[spring-kafka-4.0.2.jar:4.0.2]
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.pollAndInvoke(KafkaMessageListenerContainer.java:1479) ~[spring-kafka-4.0.2.jar:4.0.2]
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.run(KafkaMessageListenerContainer.java:1348) ~[spring-kafka-4.0.2.jar:4.0.2]
at java.base/java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1804) ~[na:na]
at java.base/java.lang.Thread.run(Thread.java:1583) ~[na:na]
Caused by: org.springframework.kafka.listener.TimestampedException: Exception thrown at 2026-02-01T06:53:25.480044400Z
at org.springframework.kafka.listener.adapter.KafkaBackoffAwareMessageListenerAdapter.onMessage(KafkaBackoffAwareMessageListenerAdapter.java:100) ~[spring-kafka-4.0.2.jar:4.0.2]
at org.springframework.kafka.listener.adapter.KafkaBackoffAwareMessageListenerAdapter.onMessage(KafkaBackoffAwareMessageListenerAdapter.java:49) ~[spring-kafka-4.0.2.jar:4.0.2]
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeOnMessage(KafkaMessageListenerContainer.java:2901) ~[spring-kafka-4.0.2.jar:4.0.2]
... 10 common frames omitted
Caused by: org.springframework.kafka.listener.ListenerExecutionFailedException: invokeHandler Failed
at org.springframework.kafka.listener.adapter.MessagingMessageListenerAdapter.checkAckArg(MessagingMessageListenerAdapter.java:519) ~[spring-kafka-4.0.2.jar:4.0.2]
at org.springframework.kafka.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:496) ~[spring-kafka-4.0.2.jar:4.0.2]
at org.springframework.kafka.listener.adapter.MessagingMessageListenerAdapter.invoke(MessagingMessageListenerAdapter.java:425) ~[spring-kafka-4.0.2.jar:4.0.2]
at org.springframework.kafka.listener.adapter.RecordMessagingMessageListenerAdapter.onMessage(RecordMessagingMessageListenerAdapter.java:92) ~[spring-kafka-4.0.2.jar:4.0.2]
at org.springframework.kafka.listener.adapter.RecordMessagingMessageListenerAdapter.onMessage(RecordMessagingMessageListenerAdapter.java:52) ~[spring-kafka-4.0.2.jar:4.0.2]
at org.springframework.kafka.listener.adapter.KafkaBackoffAwareMessageListenerAdapter.invokeDelegateOnMessage(KafkaBackoffAwareMessageListenerAdapter.java:106) ~[spring-kafka-4.0.2.jar:4.0.2]
at org.springframework.kafka.listener.adapter.KafkaBackoffAwareMessageListenerAdapter.onMessage(KafkaBackoffAwareMessageListenerAdapter.java:97) ~[spring-kafka-4.0.2.jar:4.0.2]
... 12 common frames omitted
Caused by: java.lang.IllegalStateException: No Acknowledgment available as an argument, the listener container must have a MANUAL AckMode to populate the Acknowledgment.
... 19 common frames omitted
Caused by: org.springframework.kafka.listener.TimestampedException: Exception thrown at 2026-02-01T06:53:25.480044400Z
Caused by: org.springframework.kafka.listener.ListenerExecutionFailedException: invokeHandler Failed
Caused by: java.lang.IllegalStateException: No Acknowledgment available as an argument, the listener container must have a MANUAL AckMode to populate the Acknowledgment.
> Task :com.example.emailsendconsumer.EmailSendConsumerApplication.main() FAILED
Execution failed for task ':com.example.emailsendconsumer.EmailSendConsumerApplication.main()'.
> Build cancelled while executing task ':com.example.emailsendconsumer.EmailSendConsumerApplication.main()'
* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights from a Build Scan (powered by Develocity).
> Get more help at https://help.gradle.org.
BUILD FAILED in 17s
3 actionable tasks: 2 executed, 1 up-to-date
코드 발생:
오류 발생하는 것으로 보이는 consumer 코드는 다음과 같습니다.
우선 강사님 코드와 다른 점은 Backoff 부분인데 이건 라이브러리 버전 문제 인 것 같아서 넘어갔습니다.
@Service
public class EmailSendConsumer {
@KafkaListener(
topics = "email.send",
groupId = "email-send-group"
)
@RetryableTopic(
attempts = "5",
backOff = @org.springframework.kafka.annotation.BackOff(
delay = 1000,
multiplier = 2.0
),
dltTopicSuffix = ".dlt"
)
public void consume(String message) {
System.out.println("Received message: " + message);
EmailSendMessage emailSendMessage = EmailSendMessage.fromJson(message);
if (emailSendMessage.getTo().equals("fail@naver.com")) {
// 잘못된 이메일 주소로 인해 발송 실패
throw new RuntimeException("Simulated email sending failure");
}
// 이메일 전송 로직 구현 생략 (예: SMTP 서버를 통해 이메일 전송)
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException("Email sending interrupted", e);
}
System.out.println("Email sent to: " + emailSendMessage.getTo());
}
}답변 1
0
안녕하세요, 인프런 AI 인턴입니다. 밍프런님!
Kafka의 DLT 소비 시 무한 반복되는 문제는 주로 잘못된 DLT 설정이나 ACK 모드 설정 문제로 발생할 수 있습니다. 발생한 문제에 대해 다음과 같이 해결 방안을 정리해 드립니다.
문제의 원인
DLT 설정 문제:
DLTHandler및autoStartDltHandler설정이 맞지 않을 때 발생할 수 있습니다. DLT는 실패 메시지를 보관하고 처리할 때 사용되며, 이를 방지하기 위해서는 정확한 설정이 필요합니다.ACK 모드 문제: 로그에서
No Acknowledgment available as an argument로 표시되는 에러는 ACK 모드를 수동으로 설정하지 않은 경우에 발생합니다. Kafka 리스너가 메시지를 받고 적절히 ACK하지 못하여 문제가 지속될 수 있습니다.
해결 방안
DLT 설정 확인:
@RetryableTopic어노테이션에autoStartDltHandler = false가 잘 적용되었는지 확인해주세요. 이 설정은 DLT 핸들러의 자동 시작을 방지하여 DLT 메시지가 무한 반복되지 않도록 도와줍니다.
ACK 모드 설정:
- 수동 ACK 모드를 사용하려면
KafkaListenerContainerFactory를 손봐야 합니다.AckMode.MANUAL로 설정해야 메시지가 성공적으로 처리된 후 ACK할 수 있습니다. Spring의ConcurrentKafkaListenerContainerFactory를 사용하는 경우,setAckMode(AckMode.MANUAL)로 설정해보세요.
- 수동 ACK 모드를 사용하려면
Consumer Method 검토:
consume메서드에서 ACK을 처리할 필요가 있다면,Acknowledgment객체를 인자로 받도록 수정하고 적절히ack.acknowledge()를 호출해야 합니다. 하지만 현재 로직에서는 이를 사용하지 않으므로, 오류 발생은 주로 설정 문제로 보입니다.
추가적인 유사한 문제 링크
이 내용이 밍프런님이 겪고 계신 문제 해결에 도움이 되기를 바랍니다. 현재 베타 기능으로 인해 답변에 만족하지 못하실 수 있는 점 양해 부탁드립니다. 🙏 추가적인 질문이 있으시다면, 언제든지 질문해 주세요. 지식공유자께서 빠르게 답변을 드리겠습니다.




