at most once — сообщение обрабатывается не более одного раза: потери возможны, дубликатов нет. at least once — сообщение будет обработано как минимум один раз: потерь почти нет, но возможны дубликаты. exactly once сочетает оба свойства: каждое сообщение обрабатывается ровно один раз, без потерь и без дубликатов, что сложнее и дороже в реализации.
Эти термины описывают семантику доставки и обработки сообщений в распределённых системах, брокерах сообщений, системах очередей и потоковой обработки данных. Нас обычно интересует две вещи: может ли сообщение потеряться и может ли оно быть обработано несколько раз.
Кратко различия можно свести к следующему:
at most once ("не более одного раза"): система не гарантирует доставку, но гарантирует отсутствие повторной обработки. Если во время доставки или обработки произошла ошибка (сбой сети, падение сервиса), сообщение может быть потеряно; повторной отправки/повторной обработки по умолчанию нет.at least once ("как минимум один раз"): система будет настойчиво ретраить доставку/обработку сообщения до успеха, поэтому вероятность потери минимальна. Однако из-за повторных попыток одно и то же сообщение может быть обработано несколько раз, поэтому на уровне приложения нужны идемпотентные операции или дедупликация.exactly once ("ровно один раз"): гарантируется, что каждое сообщение окажет своё действие на состояние системы один и только один раз. Это означает отсутствие и потерь, и дубликатов, что требует более сложных механизмов — транзакций, журналов, таблиц дедупликации, согласованных коммитов и т.п.Семантика at most once обычно достигается самым простым способом: сообщение отправили один раз и не храним никакого состояния о нём. Типичный пример — UDP-пакеты или "огонь и забудь"-уведомления: минимальная задержка и накладные расходы, но при сбоях часть сообщений просто пропадёт.
Семантика at least once реализуется через подтверждения и ретраи: пока получатель явно не подтвердит обработку (ack), отправитель или брокер будет пытаться доставить сообщение снова. Из-за сетевых лагов или падений сервиса подтверждение может потеряться, и тогда то же сообщение придёт повторно. Поэтому бизнес-логика, например списание денег или создание заказа, должна быть идемпотентной: повторная обработка того же события не должна приводить к повторному списанию/дублированию заказа.
exactly once на практике обычно строится поверх at least once плюс дополнительный слой гарантии, что повторная доставка не приведёт к повторному эффекту. Для этого используют, например, уникальные идентификаторы сообщений и таблицы уже обработанных ID, транзакции между очередью и базой данных, или встроенные механизмы брокера (как в Kafka с transactional producer/consumer). Такие решения сложнее, медленнее и накладнее, поэтому во многих системах достаточно at least once с аккуратно спроектированной идемпотентной бизнес-логикой.
Отметьте свой прогресс