Как Kafka обеспечивает гарантию доставки сообщений ‘At-Least-Once’ (хотя бы один раз)?

Ответ

Гарантия доставки At-Least-Once в Kafka достигается за счет комбинации настроек продюсера и механизма подтверждений от брокеров.

Ключевые механизмы:


  1. Повторные отправки (Retries): Продюсер настраивается на повторную отправку сообщений в случае временных сбоев (например, сетевых ошибок). Если продюсер не получает подтверждения от брокера в течение таймаута, он пытается отправить сообщение снова. Для этого параметр retries у продюсера должен быть больше 0.


  2. Подтверждение от брокера (acks): Это самая важная настройка. Она определяет, сколько реплик партиции должны подтвердить запись сообщения, прежде чем продюсер сочтет его успешно отправленным.

    • acks=0: Продюсер не ждет подтверждения. Возможна потеря данных.
    • acks=1: Продюсер ждет подтверждения только от лидера партиции. Если лидер падает до того, как реплики скопировали данные, сообщение может быть утеряно.
    • acks=all (или -1): Продюсер ждет подтверждения от лидера и всех синхронизированных реплик (in-sync replicas). Это самая надежная настройка, которая гарантирует, что сообщение не будет потеряно, даже если лидер выйдет из строя.

  3. Идемпотентный продюсер (enable.idempotence=true): Механизм повторных отправок может привести к дубликатам (например, брокер записал сообщение, но не успел отправить подтверждение). Чтобы этого избежать, включают идемпотентность. Продюсер присваивает каждому сообщению уникальный порядковый номер. Брокер отслеживает эти номера и отбрасывает дубликаты. Эта настройка фактически приближает гарантию к Exactly-Once на уровне продюсера.


Пример настройки надежного продюсера на Go (библиотека Sarama):

config := sarama.NewConfig()

// 1. Ждать подтверждения от всех синхронизированных реплик.
config.Producer.RequiredAcks = sarama.WaitForAll // acks=all

// 2. Включить повторные отправки при сбоях.
config.Producer.Retry.Max = 5

// 3. Включить идемпотентность для избежания дублей при ретраях.
config.Producer.Idempotent = true

// Для идемпотентности нужно ограничить количество одновременных запросов.
config.Net.MaxOpenRequests = 1

// Обязательно возвращать результат, чтобы отслеживать ошибки.
config.Producer.Return.Successes = true

producer, err := sarama.NewSyncProducer([]string{"kafka:9092"}, config)

Таким образом, связка retries > 0, acks=all и enable.idempotence=true обеспечивает надежную доставку сообщений как минимум один раз, защищая от потерь и дублирования.