awesome-everything EN
↑ Обратно к восхождению

Очереди, потоки, события

At-most-once, at-least-once, exactly-once: три контракта доставки

Суть Что означают три гарантии доставки, почему exactly-once delivery невозможна и почему at-least-once — production-стандарт.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на junior-высоте — поверхность
◷ 8 min

Payment worker обрабатывает сообщение «списать $50» и падает до того, как успевает сообщить очереди о завершении. Очередь передоставляет. Клиент списан дважды. Это не баг в коде — это поведение по умолчанию каждой production-очереди в мире.

Три контракта

Каждая message queue предлагает delivery-контракт — гарантию о том, сколько раз сообщение дойдёт до consumer-а при сбоях.

At-most-once. Брокер отправляет сообщение один раз и никогда не ретраит. Если сеть роняет сообщение — оно потеряно. Дубликатов нет, но возможна потеря. Use case: debug-логи, некритичная телеметрия. Никогда — для денег, заказов или событий, потеря которых имеет бизнес-последствия.

At-least-once. Брокер ретраит, пока consumer не отправит явный ack. Если ack потерян — брокер передоставляет. Сообщение доходит минимум один раз, но возможно и больше. At-least-once — дефолт в SQS, RabbitMQ (with ack) и Kafka с дефолтными настройками.

Exactly-once. Каждое сообщение обрабатывается ровно один раз независимо от retry. Это то, что нужно. Проблема: чистая exactly-once delivery поверх ненадёжной сети математически невозможна — Two Generals’ Problem доказывает, что две стороны поверх ненадёжного канала никогда не могут быть уверены, что обе знают одно и то же. Нельзя гарантировать, что обе стороны знают: сообщение доставлено ровно один раз.

Что можно достичь — exactly-once processing: side effect consumer-а (списание карты, отправка email, обновление строки) происходит ровно один раз, даже если брокер доставит сообщение более чем один раз. Трюк — идемпотентный consumer.

Три контракта доставки
at-most-onceОтправить один раз, без retry. Может терять. Подходит для метрик, логов.
at-least-onceRetry до ack. Может доставить 2+ раз. Production-дефолт. Требует идемпотентного consumer.
exactly-onceDelivery невозможна. Processing достижимо через consumer dedup. 20–30% overhead в Kafka.

Почему at-least-once — безопасный дефолт

At-most-once принимает потери. Для платёжной системы потерянное «списать клиента» — пропущенная транзакция, недопустимо. At-least-once принимает дубликаты. Дублирующее «списать клиента» — двойное списание, тоже плохо, но исправимо на стороне consumer. Exactly-once delivery недостижима без дорогой координации.

Конвергенция индустрии: at-least-once delivery + идемпотентный consumer. Consumer проверяет «обработал ли я этот msg ID уже?» перед действием. Дубликаты игнорируются. Очередь может ретраить без вреда.

Викторина

Какая гарантия доставки — дефолт для SQS и Kafka?

Викторина

Почему exactly-once processing достижима, а exactly-once delivery — нет?

Расставь шаги по порядку

Поставь шаги at-least-once платёжного потока с consumer-side dedup:

  1. 1 Producer генерирует уникальный msg ID и шлёт 'списать $50' в брокер
  2. 2 Брокер надёжно сохраняет сообщение и ack-ит producer
  3. 3 Consumer получает сообщение и читает ID 'msg-7a3f'
  4. 4 Consumer проверяет dedup-стор: 'обрабатывал ли msg-7a3f раньше?'
  5. 5 Dedup-стор отвечает 'нет' — consumer вызывает payment API и записывает списание
  6. 6 Consumer пишет 'msg-7a3f обработан' в dedup-стор
  7. 7 Consumer ack-ит брокер — сообщение удалено из очереди
Вспомните перед уходом
  1. 01
    Назови три гарантии доставки и по одному use case для каждой.
  2. 02
    Почему at-least-once — production-дефолт, а не exactly-once?
  3. 03
    Какое свойство должен иметь consumer, чтобы at-least-once delivery была безопасной?
Итог

Каждая очередь предлагает delivery-контракт: at-most-once принимает потери, at-least-once принимает дубликаты, exactly-once delivery невозможна — Two Generals’ Problem доказывает, что никакой конечный протокол поверх ненадёжного канала не даст обеим сторонам уверенности в согласии. Exactly-once processing достижима: consumer держит dedup-лог по msg ID и пропускает уже обработанные. Это конвертирует at-least-once delivery в exactly-once processing ценой dedup-стора — вот почему at-least-once — production-дефолт в SQS, Kafka и RabbitMQ.

Связанные уроки
встречается в202
Продолжить восхождение ↑Три ножки сбоя — где реально происходят дубликаты и потери
хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.