Как регулируется вычитка сообщений в Kafka и как система понимает, что сообщение вычитано
Что проверяют
Понимаете ли вы, что Kafka не удаляет сообщение после чтения, а «прочитано» это позиция группы потребителей. Для QA следом идёт практика: как проверить, что сервис не теряет и не дублирует сообщения при падении, и где посмотреть лаг.
Как отвечать
Сообщение лежит в партиции топика и имеет offset, порядковый номер внутри партиции. Хранится оно по политике retention (retention.ms, по умолчанию 7 дней), независимо от того, читал его кто-то или нет.
- consumer group: потребители с одним
group.idделят партиции, одну партицию в группе читает один потребитель. Другая группа читает те же сообщения независимо; - коммит offset: группа сохраняет в служебный топик
__consumer_offsetsномер следующего сообщения, которое нужно прочитать. Это и есть признак «вычитано»; - auto-commit: по умолчанию
enable.auto.commit=true, коммит раз вauto.commit.interval.ms(5 секунд) при очередномpoll(); - ручной коммит:
commitSync()после обработки даёт at-least-once, при падении часть сообщений придёт повторно; - старт без коммита:
auto.offset.reset, по умолчаниюlatest, то есть новая группа не увидит старые сообщения.
Темп чтения регулируют max.poll.records (по умолчанию 500) и max.poll.interval.ms: если обработка пачки идёт дольше, потребителя исключат из группы и начнётся ребалансировка.
Для тестирования: лаг, то есть разницу между концом партиции и закоммиченным offset, смотрят через kafka-consumer-groups.sh --describe. Сценарии: убить потребителя посреди пачки и проверить дубли, перечитать топик через --reset-offsets.
Где спотыкаются
Говорят, что сообщение читается один раз и удаляется. Это модель классической очереди, а в Kafka сообщение читают сколько угодно групп, пока его не удалит retention.
Считают, что auto-commit означает «подтверждено после обработки». Коммит фиксирует всё, что выдал прошлый poll(), и если обработка ушла в другой поток, offset закоммитится раньше, чем работа закончится. При падении такие сообщения теряются.
Путают гарантии: ручной коммит без идемпотентного обработчика не даёт exactly-once. Для этого нужны транзакции Kafka или дедупликация на стороне потребителя.