Операция выполнена!
Закрыть
Хабы: Go, Проектирование и рефакторинг, Микросервисы, Программирование, Высоконагруженные системы

Представим обычную обработку заказа. Сервис заказов публикует событие order.created. Сервис склада получает его и резервирует товар в PostgreSQL. После успешной транзакции обработчик должен отправить RabbitMQ подтверждение (Ack), чтобы broker удалил сообщение из queue.

Но процесс может остановиться после записи в PostgreSQL и до отправки Ack. RabbitMQ не знает, успел ли сервис зарезервировать товар. Broker видит только неподтверждённое сообщение, поэтому доставляет его ещё раз. С точки зрения доставки это правильное поведение. С точки зрения бизнеса один заказ теперь может зарезервировать товар дважды.

Другой сбой возникает раньше: PostgreSQL временно недоступен, и обработчик не может начать работу. Если сразу вернуть сообщение в queue через отрицательное подтверждение Nack(requeue=true), RabbitMQ почти немедленно доставит его снова. Пока база не восстановилась, все попытки будут бесполезными. Нужны задержка и ограничение числа повторов. При этом отложенное сообщение может пропустить вперёд более новые события, поэтому отдельно придётся решить вопрос порядка.

Так одна операция превращается в несколько независимых участков: запись события, публикация, хранение в broker, обработка и подтверждение. Между соседними участками остаются моменты, когда одна сторона уже выполнила действие, а другая ещё не получила подтверждение.

В статье разберём эти моменты по всему пути сообщения. Затем построим практическую схему для RabbitMQ и Go: добавим ограниченные повторы через retry queues, время жизни сообщения (TTL) и dead letter exchange, сделаем обработчик идемпотентным и определим, куда отправлять сообщения, которые не удалось обработать автоматически. В конце сравним этот подход с Kafka, NATS JetStream и Amazon SQS.

Читать далее
Читайте также
НОВОСТИ

ПИШИТЕ

Техническая поддержка проекта ВсеТут

info@vsetut.pro