Как обрабатывать битые сообщения в Kafka, чтобы не блокировать обработку новых
Что проверяют
Понимаете ли вы, почему одно битое сообщение вообще способно остановить обработку. Kafka держит порядок внутри партиции, и консьюмер, который бесконечно ретраит сообщение и не двигает offset, стоит вместе со всей партицией. Следом спрашивают, как отличить временную ошибку от постоянной и что делать с отложенными сообщениями.
Как отвечать
Сначала классифицируйте ошибки, потом стройте маршрут:
- постоянные: неразбираемый JSON, нарушение схемы, невалидные данные. Повтор не поможет, сообщение сразу уходит в dead letter topic, например
orders.dlq; - временные: недоступна база, таймаут внешнего API. Пара повторов на месте с экспоненциальной задержкой через Polly, затем перекладывание в retry-топики с нарастающей задержкой и только потом DLQ.
В клиенте Confluent.Kafka встроенного DLQ нет, это делается руками. Надёжнее читать значение как byte[] и десериализовать самим: тогда битый payload у вас в руках, а не спрятан в исключении из Consume. Порядок действий: отправить в DLQ, дождаться подтверждения ProduceAsync и только потом фиксировать offset. Для этого выключают EnableAutoOffsetStore и вызывают StoreOffset после успешной обработки или отправки. В заголовки DLQ-сообщения кладите исходные топик, партицию, offset и текст ошибки, иначе разбирать их будет не по чему.
Две оговорки сильно усилят ответ. Retry-топики ломают порядок по ключу: если он важен, сломавшийся ключ паркуют вместе со следующими его событиями. Доставка остаётся at-least-once, поэтому обработчик должен быть идемпотентным.
Где спотыкаются
Оборачивают обработку в try/catch и в catch ретраят без лимита. Партиция встаёт, lag растёт, а заметят это, когда сработает алерт на отставание.
Сохраняют offset до обработки, оставляя автоматические настройки по умолчанию. Сервис падает посреди обработки, и сообщение, которое уже числится прочитанным, теряется.
Заводят DLQ и забывают о нём. Без алерта на рост топика и инструмента повторной отправки после фикса это кладбище данных, о котором вспоминают при жалобе клиента.