Как происходит взаимодействие сервисов через Kafka и дублируются ли сообщения
Что проверяют
Понимаете ли вы, какие гарантии Kafka даёт на самом деле, и умеете ли заложить обработку дублей в требования, а не оставить её на усмотрение разработчиков. Следом обычно спрашивают, как бы вы описали такую интеграцию в постановке.
Как отвечать
Сначала механика:
- топик и партиции: продюсер пишет сообщение в топик, партиция выбирается по ключу. Порядок гарантируется только внутри партиции, поэтому все события одного заказа должны идти с одним ключом;
- consumer group: партиции делятся между экземплярами сервиса, каждую партицию в группе читает один потребитель;
- offset: потребитель сам фиксирует, до какого места дочитал. Сообщение после чтения не удаляется, оно живёт до истечения retention, и другой сервис со своей группой прочитает его независимо.
Теперь про дубли. Ответ «да, бывают», и важно назвать где. Повтор отправки после таймаута у продюсера закрывает идемпотентный продюсер (enable.idempotence=true, по умолчанию с Kafka 3.0). Главный источник дублей это потребитель: он обработал сообщение, но не успел зафиксировать offset из-за падения или ребалансировки и после рестарта прочитает его снова. Это семантика at-least-once, на практике самая частая. Exactly-once через транзакции работает только в цепочке «прочитал из Kafka, записал в Kafka» и не распространяется на запись в базу или вызов внешнего API.
Вывод для аналитика: в требованиях фиксируется идемпотентность потребителя. У сообщения есть уникальный идентификатор, потребитель хранит обработанные id или делает операцию безопасной для повтора. Туда же ключ партиционирования, схема сообщения и её версионирование, судьба сообщения, которое не удалось обработать (retry-топик, DLQ).
Где спотыкаются
Говорят, что Kafka гарантирует exactly-once и дублей не бывает. Это верно только для узкого сценария внутри самой Kafka.
Путают Kafka с классической очередью и думают, что сообщение исчезает после прочтения.
Забывают про порядок: описывают события «создан», «оплачен», «отменён» без общего ключа и получают отмену раньше создания.