Перейти к содержимому

Message Queue

Message Queue (очередь сообщений) — это паттерн асинхронной интеграции, при котором отправитель помещает сообщение в буфер, а один из нескольких получателей забирает его для обработки, что обеспечивает развязку компонентов, балансировку нагрузки и надежную доставку.

Введение: Живая очередь в банке

Представьте, что вы пришли в банк. Стоят несколько касс. Вы подходите к свободной кассе — вас обслуживают. Если все кассы заняты, вы встаёте в общую очередь. Когда касса освобождается, подходит следующий клиент. Клиенты не знают, к какой кассе пойдут. Кассиры не знают, кто следующий. Очередь управляет всем процессом.

В мире программ очередь сообщений работает так же. Программы-отправители кладут сообщения в очередь. Программы-получатели забирают сообщения из очереди. Каждое сообщение достаётся одному получателю. Если получателей несколько, они делят сообщения между собой.

Message Queue (Очередь сообщений) — это паттерн интеграции, при котором сообщение доставляется ровно одному получателю. Очередь выступает буфером между отправителем и получателем, позволяя им работать независимо и в разном темпе.

Это самый простой и самый распространённый паттерн обмена сообщениями. Он лежит в основе многих систем: от обработки заказов до фоновых задач. Для системного аналитика понимание очереди сообщений — это база для проектирования асинхронных и слабосвязанных систем.

Ключевые принципы

Разделение отправителя и получателя

Отправитель:
  - Не знает IP получателя
  - Не знает, сколько получателей
  - Не знает, доступен ли получатель

Получатель:
  - Не знает, кто отправил
  - Не знает, сколько отправителей

Буферизация

Если получатель временно недоступен:
  - Сообщения накапливаются в очереди
  - При восстановлении получатель обрабатывает накопленные сообщения

Балансировка нагрузки

Несколько получателей:
  - Каждое сообщение достаётся одному получателю
  - Распределение: round-robin или по готовности

FIFO (First In, First Out)

Порядок:
  - Сообщения обрабатываются в порядке поступления
  - Первым пришёл — первым ушёл

Как это работает

    graph LR
    A[Отправитель 1] --> Q[Очередь]
    B[Отправитель 2] --> Q
    Q --> C[Получатель 1]
    Q --> D[Получатель 2]
    Q --> E[Получатель 3]
  

Шаг 1: Отправка

Отправитель создаёт сообщение и отправляет его в очередь. Не ждёт ответа (асинхронно). Может продолжить свою работу.

Шаг 2: Хранение

Очередь хранит сообщение до тех пор, пока получатель не заберёт его и не подтвердит обработку. Сообщение может храниться в памяти или на диске.

Шаг 3: Получение

Получатель забирает сообщение из очереди. Если получателей несколько, сообщение достаётся одному. Получатель обрабатывает сообщение. После успешной обработки подтверждает (ack). Очередь удаляет сообщение.

Шаг 4: Повтор при ошибке

Сценарий:
  1. Получатель забрал сообщение
  2. Обработка упала
  3. Подтверждение не пришло
  4. Сообщение возвращается в очередь
  5. Другой получатель обработает

Свойства очереди

Point-to-Point (Точка-точка)

Одно сообщение — один получатель. Это главное свойство очереди.

Отличие от Pub-Sub:
  - Pub-Sub: сообщение получают все подписчики
  - Message Queue: сообщение получает один получатель

Асинхронность

Отправитель не ждёт ответа. Получатель может обрабатывать сообщение в удобное время.

Надёжность

Сообщения не теряются (при настройке persistent и подтверждениях). Хранятся на диске до обработки.

Балансировка нагрузки

Несколько получателей автоматически распределяют сообщения между собой.

Режимы работы

Автоматическое подтверждение (auto-ack)

Алгоритм:
  1. Получатель забрал сообщение
  2. Брокер сразу удаляет сообщение из очереди
  3. Получатель обрабатывает

Риск:
  - Если обработка упала — сообщение потеряно

Ручное подтверждение (manual ack)

Алгоритм:
  1. Получатель забрал сообщение
  2. Обрабатывает
  3. После успеха — подтверждает (ack)
  4. Брокер удаляет сообщение

Плюс:
  - Сообщение не потеряется при падении

Минус:
  - Сложнее реализовать

Распределение сообщений

Round-robin (по умолчанию):
  - Сообщение 1 → получатель 1
  - Сообщение 2 → получатель 2
  - Сообщение 3 → получатель 1
  - Сообщение 4 → получатель 2

Fair dispatch (с prefetch):
  - Учитывает готовность получателя
  - Не даёт новое сообщение, пока предыдущее не подтверждено

Где используется

1. Обработка заказов в интернет-магазине

Отправитель:
  - Веб-сайт (пришёл новый заказ)

Очередь:
  - orders.queue

Получатели:
  - 5 воркеров, обрабатывающих заказы

Почему очередь:
  - Заказ должен быть обработан один раз
  - Воркеров можно добавлять при росте нагрузки
  - Если все воркеры заняты — заказы ждут в очереди

2. Отправка email

Отправитель:
  - Сервис регистрации (нужно отправить письмо)

Очередь:
  - email.queue

Получатели:
  - 10 SMTP-воркеров

Почему очередь:
  - SMTP-сервер может быть медленным
  - Очередь сглаживает пики
  - При ошибке письмо можно отправить повторно

3. Ресайз изображений

Отправитель:
  - Пользователь загрузил изображение

Очередь:
  - image.resize.queue

Получатели:
  - Воркеры для ресайза

Почему очередь:
  - Ресайз может занимать секунды
  - Пользователь не должен ждать

4. Асинхронная обработка данных

Отправитель:
  - API, принявший данные

Очередь:
  - data.processing.queue

Получатели:
  - Аналитический движок

Почему очередь:
  - Обработка может быть долгой
  - API должен ответить быстро

Преимущества и недостатки

Преимущества

ПреимуществоОбъяснение
Слабая связанностьОтправитель и получатель не знают друг о друге
АсинхронностьОтправитель не ждёт обработки
БуферизацияСообщения накапливаются при перегрузке получателя
Балансировка нагрузкиАвтоматическое распределение между воркерами
НадёжностьСообщения не теряются (с подтверждениями)
МасштабированиеЛегко добавить новых получателей

Недостатки

НедостатокОбъяснение
Нет ответаОтправитель не знает результат обработки
Нет историиСообщение удаляется после обработки
ЗадержкаСообщение может ждать в очереди
Сложность отладкиТрудно отследить путь сообщения

Реализации

БрокерПоддержка очередейОсобенности
RabbitMQДа (основной паттерн)Гибкая маршрутизация, подтверждения
ActiveMQДаJava-экосистема
AWS SQSДа (управляемый)Простота, интеграция с AWS
Redis (List)ДаЛёгкий, быстрый
KafkaНет (эмулируется через consumer group)Не очередь, а журнал

Message Queue vs Publish-Subscribe

ХарактеристикаMessage QueuePublish-Subscribe
ПолучателейОдинМного
БалансировкаДаНет (все получают всё)
Типичное применениеЗадачи, работыСобытия, уведомления
Сообщение после прочтенияУдаляетсяКопируется подписчикам

Message Queue vs Kafka

ХарактеристикаMessage QueueKafka
МодельОчередьЖурнал
После прочтенияСообщение удаляетсяСообщение остаётся
ReplayНетДа
ПорядокFIFOВнутри партиции
Типичное применениеЗадачиПотоки событий

Практический пример: Обработка заказов

Схема

    graph LR
    A[Веб-сайт] -->|создан заказ| Q[orders.queue]
    Q --> W1[Воркер 1]
    Q --> W2[Воркер 2]
    Q --> W3[Воркер 3]
  

Характеристики

Очередь:
  - durable: true (сохраняется при перезапуске)
  - persistent: true (сообщения на диске)

Отправитель (веб-сайт):
  - Отправляет заказ
  - Не ждёт обработки
  - Мгновенно отвечает клиенту

Получатели (воркеры):
  - manual ack
  - ack после записи в БД
  - prefetch = 5 (не более 5 неподтверждённых)

Преимущества для бизнеса

Пользователь:
  - Не ждёт, пока заказ обработается
  - Получает мгновенный ответ "заказ принят"

Магазин:
  - Может масштабировать воркеров в час пик
  - Не теряет заказы при падении воркера
  - Может обрабатывать пиковые нагрузки

Распространённые ошибки

Ошибка 1: Очередь как база данных

Хранят в очереди сообщения, которые нужно сохранить надолго.

Решение: Очередь — для передачи. База данных — для хранения.

Ошибка 2: Очередь для синхронных вызовов

Отправляют сообщение и ждут ответа в той же очереди.

Решение: Для синхронных вызовов используйте HTTP/gRPC. Для RPC через очередь — отдельный паттерн с reply_to.

Ошибка 3: Нет мониторинга глубины

Очередь растёт, никто не знает. Воркеры не справляются.

Решение: Мониторинг queue depth, алерты при росте.

Ошибка 4: Бесконечный retry

Сообщение падает, возвращается в очередь, снова падает, бесконечно.

Решение: Dead Letter Queue после N попыток.

Ошибка 5: Одна очередь на всё

Все типы сообщений в одной очереди. Сложно масштабировать, приоритеты не работают.

Решение: Разные очереди под разные типы задач.

Резюме

  1. Message Queue — паттерн, при котором сообщение доставляется ровно одному получателю. Основа для очередей задач, распределения работы, асинхронной обработки.

  2. Ключевые свойства: point-to-point, асинхронность, буферизация, балансировка нагрузки, FIFO.

  3. Где используется: обработка заказов, отправка email, ресайз изображений, фоновая обработка.

  4. Преимущества: слабая связанность, масштабируемость, надёжность.

  5. Недостатки: нет ответа отправителю, нет истории, возможна задержка.

  6. Реализации: RabbitMQ, ActiveMQ, AWS SQS, Redis.

Проверка знаний

Вопрос 1 из 4
Что характеризует паттерн Message Queue?
Зачем очереди используют для фоновой обработки?
Что даёт manual ack в паттерне очереди?
Когда Message Queue подходит хуже?

Вопросы, где были ошибки