Как в Spring Kafka обычно строят retry и dead letter topic?
- Что такое @RetryableTopic?
Два способа: блокирующий — DefaultErrorHandler с BackOff и DeadLetterPublishingRecoverer (повторы на месте, партиция ждёт); неблокирующий — @RetryableTopic: запись уходит в retry-топики с задержкой, а партиция продолжает обрабатываться.
- Постоянные ошибки (валидация, десериализация) — сразу в DLT без повторов
- Неблокирующий повтор нарушает порядок для ключа
- DLT — с заголовками причины, исходного топика и offset
А ещё У DLT должен быть владелец, алерт и способ переиграть сообщения
Подробно
Блокирующий повтор:
@Bean
DefaultErrorHandler errorHandler(KafkaTemplate<Object, Object> t) {
var h = new DefaultErrorHandler(new DeadLetterPublishingRecoverer(t),
new ExponentialBackOff(1000, 2.0) {{ setMaxElapsedTime(30_000); }});
h.addNotRetryableExceptions(ValidationException.class);
return h;
}
Запись повторяется на месте; пока идут повторы, остальные записи партиции ждут — порядок сохраняется, но долгая отсрочка задерживает поток. Повторы держат потребителя — нельзя ставить отсрочку длиннее max.poll.interval.ms.
Неблокирующий повтор:
@RetryableTopic(attempts = "4", backoff = @Backoff(delay = 1000, multiplier = 10),
exclude = ValidationException.class)
@KafkaListener(topics = "payments")
void handle(PaymentEvent e) { ... }
Spring создаёт топики payments-retry-0, -retry-1, … и payments-dlt. Упавшая запись публикуется в retry-топик и будет прочитана после задержки, а основная партиция обрабатывается дальше. Цена — потеря порядка для этого ключа и больше топиков.
Что выбрать: порядок важен (события одной сущности) — блокирующий с небольшим числом попыток; порядок не важен, важна пропускная способность — неблокирующий. В обоих случаях: неповторяемые исключения — сразу в DLT, десериализация — через ErrorHandlingDeserializer, мониторинг DLT.
Что хотят услышать
- Блокирующий и неблокирующий повтор, их компромиссы.
- DeadLetterPublishingRecoverer и @RetryableTopic.
- Неповторяемые ошибки и порядок.
Частые ошибки
- Повторять ошибки валидации.
- Отсрочка дольше max.poll.interval.ms в блокирующем режиме.
Проверьте себя
Один верный вариант. Подумайте, потом откройте ответ.
Показать варианты и ответ
- ✗Бесконечно повторяют сообщение, пока не получится
- ✗Откатывают offset в начало топика и заново перечитывают все сообщения начиная с первой ошибки
- ✗Удаляют сообщение при первой же ошибке
- ✓DefaultErrorHandler ретраит с backoff, затем запись уходит в DLT
Что спросят дальше
- Что хранить в DLT headers?
- Когда retry topic лучше blocking retry?
Разбор темы
- Spring Kafka
KafkaTemplate, @KafkaListener, listener containers, offset ack, error handling, retries и DLT.
Связанные вопросы
- Чем неблокирующий повтор через отдельные retry-топики лучше повтора прямо в обработчике? Senior
- Какие ошибки обработки сообщения имеет смысл повторять, а какие нет? Middle
- Что важно предусмотреть при проектировании dead letter queue? Middle
- Как @KafkaListener связан с listener container и offset commit? Senior
Разбор собеседования с sotto
После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.