Очереди сообщений и асинхронность

Как разорвать жёсткую связь между сервисами и пережить всплески нагрузки.

Очередь сообщений — буфер между producer и consumer, который позволяет обрабатывать задачи асинхронно, развязывая отправителя и получателя по времени и нагрузке.

Зачем нужна очередь

Если загрузка фото запускает синхронно нарезку превью, распознавание и индексацию, пользователь ждёт всё это. Вынесем тяжёлую работу в очередь: API быстро отвечает «принято», а consumer'ы делают остальное в фоне. Так система становится отзывчивее и устойчивее к пикам.

Producer -> [ Очередь ] -> Consumer 1
                       -> Consumer 2  (масштабируем независимо)

Три главные выгоды

ВыгодаСуть
РазвязкаProducer не знает про consumer, можно менять независимо
Сглаживание пиковВсплеск копится в очереди, обрабатывается ровно
Масштаб consumer'овДобавляем обработчиков под рост очереди

Гарантии доставки

Большинство брокеров дают at-least-once: сообщение точно дойдёт, но может прийти повторно. Отсюда требование — consumer должен быть идемпотентным, чтобы повторная обработка не навредила (например, не списать дважды). Exactly-once дорог и редко нужен.

Как работает под капотом

Очередь превращает синхронную цепочку «запрос -> вся работа -> ответ» в асинхронную «запрос -> ответ + задача в фоне». Это вводит новые заботы: что если consumer упал (сообщение вернётся в очередь), что с «ядовитыми» сообщениями (dead-letter queue), как не потерять порядок (партиции/ключи). На собеседовании достаточно назвать эти заботы — это показывает зрелость.

Частые ошибки

  • Делать всё синхронно и блокировать пользователя на тяжёлой работе.
  • Забыть про идемпотентность при at-least-once доставке.
  • Не предусмотреть dead-letter queue для битых сообщений.

Итог

  • Очередь развязывает сервисы, сглаживает пики и масштабирует фон.
  • at-least-once -> consumer обязан быть идемпотентным.
  • Помните про падения consumer'ов, dead-letter и порядок сообщений.
Проверьте себя
1. Какая из выгод НЕ относится к очередям сообщений?
AРазвязка producer и consumer
BСглаживание всплесков нагрузки
CМгновенная сильная согласованность всех данных
DНезависимое масштабирование обработчиков
2. Почему consumer должен быть идемпотентным при at-least-once доставке?
AЧтобы ускорить обработку
BПотому что сообщение может прийти повторно, и повтор не должен навредить
CЧтобы уменьшить размер очереди
DИдемпотентность нужна только producer'у