Какие существуют уровни гарантии доставки сообщений в брокерах

Ответ

Гарантия доставки — это соглашение о надёжности, которое система обязуется выполнить при передаче сообщения от отправителя (producer) к получателю (consumer). Существует три основных уровня:

  1. At-most-once (не более одного раза)

    • Сообщение доставляется 0 или 1 раз. Это самый быстрый, но наименее надёжный уровень. Сообщения могут быть утеряны при сбое сети или падении потребителя до подтверждения.
    • Применение: Некритические данные, где потеря сообщения допустима (например, сбор метрик, логов).
  2. At-least-once (как минимум один раз)

    • Гарантирует, что сообщение будет доставлено, но допускает дубликаты. Потребитель должен подтвердить (acknowledge) получение сообщения. Если подтверждение не приходит, брокер отправляет сообщение повторно.
    • Применение: Самый распространённый сценарий, где важна доставка, а потребитель спроектирован идемпотентным (повторная обработка дубля не вызывает проблем).
  3. Exactly-once (ровно один раз)

    • Самый строгий уровень: каждое сообщение доставляется и обрабатывается ровно один раз. Требует сложных механизмов, таких как транзакции или дедупликация на стороне потребителя и брокера.
    • Применение: Критически важные системы, где дубликаты недопустимы (например, финансовые транзакции).

Пример реализации At-least-once в RabbitMQ:

import pika

connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()

# 1. Объявляем очередь как 'durable', чтобы она пережила перезапуск брокера.
channel.queue_declare(queue='task_queue', durable=True)

# 2. Включаем подтверждения от брокера (Publisher Confirms).
channel.confirm_delivery()

# 3. Отправляем сообщение с 'delivery_mode=Persistent',
# чтобы оно сохранялось на диск.
channel.basic_publish(
    exchange='',
    routing_key='task_queue',
    body='Task message',
    properties=pika.BasicProperties(
        delivery_mode=pika.DeliveryMode.Persistent
    )
)
print(" [x] Sent 'Task message'")
connection.close()

На стороне потребителя для этой схемы необходимо отправлять подтверждения (channel.basic_ack()) после успешной обработки сообщения.