Что происходит с сообщением в Kafka после его прочтения
Что проверяют
То же понимание журнала, но с уклоном в клиент: как в Go устроена фиксация оффсетов и чем отметка обработанного сообщения отличается от коммита. Здесь легко выдать, что пример скопирован из документации библиотеки, а что произойдёт при аварийной остановке сервиса, человек не думал.
Как отвечать
Само сообщение остаётся на месте. Журнал партиции дописывается в конец и от чтения не меняется, сообщения удаляются по сроку хранения или по объёму, целыми сегментами, а при уплотнении по ключу остаётся последнее значение. Потребитель двигает только свой оффсет, по нему группа знает, откуда продолжать после перезапуска.
Дальше про Go, потому что фиксация в разных клиентах устроена по-разному и это стоит назвать прямо:
- отметка сообщения внутри сессии группы это ещё не коммит, реальная фиксация уходит по таймеру автоматической фиксации или при корректном завершении сессии;
- у читателя с группой чтение одной функцией подтверждает оффсет само, а ручной режим требует отдельного вызова уже после обработки;
- всё, что отмечено, но не зафиксировано, после жёсткой остановки процесса будет выдано заново.
Отсюда два практических правила. Первое: завершаться по контексту и обязательно закрывать потребителя, иначе группа заметит пропажу только по таймауту, и всё это время партиция стоит. Второе: одна горутина на партицию, порядок гарантируется только внутри партиции, а распараллеливание по отдельным сообщениям ломает и порядок, и смысл оффсета.
Где спотыкаются
Считают отметку сообщения фиксацией. После жёсткого завершения сервис перечитывает целую пачку заново, и появляются дубликаты там, где их никто не ждал.
Раскидывают обработку по горутинам на каждое сообщение, а оффсет двигают сразу после чтения. Оффсет обгоняет работу: сообщение числится обработанным, хотя горутина ещё в пути или уже упала с паникой.
Полагаются на доставку ровно один раз, потому что так написано в настройках продюсера. Идемпотентность и транзакции на стороне записи не отменяют повторной выдачи потребителю, и защищаться от повторов всё равно приходится ключом в своей базе.