Ответ
Consumer в Kafka не "запоминает данные", а отслеживает свою позицию в логе партиции топика. Эта позиция называется смещением (offset).
Offset — это просто целое число, которое указывает на номер следующего сообщения, которое Consumer должен прочитать. Управление offset'ами — ключевая задача для обеспечения надежной доставки сообщений.
Где хранится offset?
По умолчанию, Consumer-группы хранят свои offset'ы в специальном внутреннем топике Kafka под названием __consumer_offsets
.
Как происходит отслеживание (Commit)?
Процесс сохранения offset'а называется коммитом (commit). Существует две основные стратегии:
1. Автоматический коммит (Auto Commit)
- Как работает: Consumer периодически (например, каждые 5 секунд) автоматически коммитит последний полученный offset.
- Плюсы: Простота настройки (
enable.auto.commit=true
). - Минусы: Низкие гарантии доставки. Возможна как потеря сообщений (если приложение упало после обработки, но до авто-коммита), так и повторная обработка (если коммит произошел, а обработка не удалась).
2. Ручной коммит (Manual Commit)
- Как работает: Разработчик полностью контролирует, когда коммитить offset. Обычно это делается после успешной обработки сообщения или пачки сообщений.
- Плюсы: Высокая надежность и гибкость. Позволяет реализовать семантики
at-least-once
(как минимум один раз) иexactly-once
(ровно один раз). - Минусы: Требует больше кода и внимания от разработчика.
Виды ручного коммита:
- Синхронный (
CommitSync
): Блокирует выполнение, пока брокер не подтвердит коммит. Надежно, но медленнее. - Асинхронный (
CommitAsync
): Не блокирует выполнение. Быстрее, но нет гарантии, что коммит прошел успешно.
Пример логики ручного коммита (псевдокод):
// Бесконечный цикл чтения сообщений
for {
// 1. Получаем сообщение от Kafka
msg := consumer.Poll()
// 2. Обрабатываем сообщение (например, сохраняем в базу данных)
err := processMessage(msg)
// 3. Если обработка прошла успешно, коммитим offset
if err == nil {
// Сообщаем Kafka, что это сообщение и все предыдущие успешно обработаны
consumer.Commit(msg.Offset() + 1)
} else {
// Логируем ошибку и решаем, что делать дальше
// (например, повторить попытку или отправить в Dead Letter Queue)
}
}
Итог: Consumer отслеживает прогресс с помощью offset'ов, которые сохраняются (коммитятся) в Kafka. Ручной коммит является предпочтительным способом для построения надежных систем.