Как гарантировать at-least-once или exactly-once доставку сообщений?
Подробный ответ
At-most-once, at-least-once и exactly-once
| Семантика | Что гарантирует | Основной риск |
|---|---|---|
| At-most-once | Сообщение обработается не более одного раза | Сообщение может потеряться |
| At-least-once | Сообщение будет доставлено хотя бы раз | Возможна повторная обработка |
| Exactly-once | Итоговый эффект операции возникает один раз | Сложно обеспечить между независимыми системами |
Как получить at-least-once
Получатель подтверждает обработку только после успешного выполнения бизнес-операции. Если получатель упал до подтверждения, брокер повторно доставит сообщение другому экземпляру. Так риск потери снижается, но появляется риск дубликата.
1. Получатель получает сообщение
2. Выполняет бизнес-операцию
3. Сохраняет результат
4. Подтверждает обработку брокеру
Если сбой произошёл до шага 4,
сообщение может быть доставлено повторно.Почему exactly-once сложно
Представим задачу: списать деньги во внешнем платёжном сервисе, сохранить заказ в базе и подтвердить сообщение брокеру. Если процесс упадёт между этими шагами, нельзя одним обычным действием атомарно гарантировать результат во всех независимых системах.
Практический путь к exactly-once effect
каждому сообщению назначают уникальный идентификатор;
получатель хранит факт обработки идентификатора в базе данных;
бизнес-эффект и запись об обработке выполняют в одной локальной транзакции;
повторное сообщение с тем же идентификатором не создаёт новый эффект;
для внешних API передают идемпотентный ключ, если сервис его поддерживает.
processed_messages:
message_id: string, unique
processed_at: timestamp
business_operation:
operation_id: string, unique
status: completedOutbox pattern
Чтобы не потерять событие после изменения данных, бизнес-изменение и запись исходящего события сохраняют в одной транзакции базы. Отдельный процесс читает таблицу исходящих событий и публикует их в брокер. Это называется outbox pattern.
Как ответить на собеседовании
Для at-least-once подтверждаю сообщение только после успешной обработки, поэтому допускаю дубликаты. Для exactly-once effect делаю получателя идемпотентным: использую message ID, уникальное ограничение и одну транзакцию для записи результата и отметки обработки. Между несколькими независимыми системами exactly-once редко обеспечивается одной настройкой, поэтому нужны идемпотентность, outbox и идемпотентные ключи внешних вызовов.
Оцени свой прогресс