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

Через брокер сообщений

Брокер сообщений — центральная шина (Kafka, RabbitMQ), системы общаются через него, а не напрямую. Плюсы: слабая связанность, асинхронность, буферизация, надёжность. Минусы: сложность, задержка. Очередь — одному получателю. Топик (pub-sub) — многим. DLQ — очередь для битых сообщений.

Введение: Диспетчер, а не прямые звонки

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

Теперь представьте, что есть телефонная станция. Вы подключаетесь к станции, станция соединяет вас с нужным абонентом. Новый друг — не нужно тянуть новый провод. Достаточно, чтобы он тоже подключился к станции.

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

Это архитектурный паттерн, при котором все системы подключаются к центральному посреднику — брокеру сообщений. Брокер принимает сообщения от отправителей и доставляет их получателям. Системы не знают друг о друге. Они знают только о брокере.

Для системного аналитика брокер сообщений — это инструмент для слабой связанности, асинхронной обработки, масштабирования и надёжности. Выбор между “точка-точка” и “через брокер” — одно из ключевых архитектурных решений.

Как это выглядит

    graph TD
    A[Система A] -->|сообщение| B[Брокер]
    C[Система C] -->|сообщение| B
    B -->|сообщение| D[Система D]
    B -->|сообщение| E[Система E]
    B -->|сообщение| F[Система F]
  

Примеры брокеров:

БрокерТипОсобенность
KafkaЛог-ориентированныйВысокая производительность, хранение событий
RabbitMQОчереднойГибкая маршрутизация, сложные сценарии
ActiveMQОчереднойJava-экосистема
AWS SQSОчереднойУправляемый, облачный
AWS SNSPub/SubУправляемый, облачный
NATSЛёгкийВысокая скорость, простота

Модели доставки

Очередь (Queue)

Одно сообщение — одному получателю.

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

Пример: Задача на обработку. Кто первый взял — тот и обработал. Остальные задачу не видят.

Топик (Topic) / Pub-Sub

Одно сообщение — многим получателям.

    graph LR
    A[Отправитель] -->|сообщение| T[Топик]
    T -->|сообщение| B[Подписчик 1]
    T -->|сообщение| C[Подписчик 2]
    T -->|сообщение| D[Подписчик 3]
  

Пример: Событие “пользователь создан”. Все системы, которым это важно (CRM, биллинг, маркетинг), получают копию.

Синхронный vs Асинхронный через брокер

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

Плюсы и минусы

Плюсы

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

Минусы

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

Режимы доставки

At-most-once (не более одного раза)

Сообщение может потеряться, но не будет доставлено дважды.

Где используется: Логи, метрики (потеря одного лога не страшна).

At-least-once (не менее одного раза)

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

Где используется: Большинство сценариев. Требует идемпотентности на получателе.

Exactly-once (ровно один раз)

Сообщение не потеряется и не дублируется.

Где используется: Финансы, критические данные. Дорого, сложно.

Порядок сообщений

ГарантияЧто значитПримеры
Порядок в рамках партицииВ одной партиции порядок сохраняетсяKafka
Глобальный порядокВсе сообщения упорядоченыРедко, дорого
Без гарантийПорядок не сохраняетсяRabbitMQ (по умолчанию)

Для аналитика: Если важен порядок (например, “сначала создание, потом обновление”), выбирайте брокер с гарантиями порядка.

Требования к надёжности

Персистентность (сохранение на диск)

УровеньЧто значитРиск потери
In-memoryСообщения только в RAMПри сбое брокера — потеря
На дискеСообщения на дискеПри сбое диска — потеря (редко)
РеплицированноеНа нескольких узлахОчень низкий

Подтверждения (Acknowledgment)

    sequenceDiagram
    participant A as Отправитель
    participant B as Брокер
    participant C as Получатель
    
    A->>B: Сообщение
    B-->>A: ACK (я получил)
    B->>C: Сообщение
    C-->>B: ACK (я обработал)
    B-->>B: Удалить сообщение
  

Что даёт: Сообщение не потеряется, если получатель упал до обработки.

Dead Letter Queue (DLQ)

Очередь для сообщений, которые не удалось обработать.

    graph LR
    A[Основная очередь] -->|ошибка| B[DLQ]
    B -->|анализ| C[Администратор]
  

Когда сообщение попадает в DLQ:

  • Превышено количество попыток (например, 3)
  • Сообщение невалидно (нельзя обработать в принципе)
  • Таймаут обработки

Для СА: DLQ — источник данных о проблемах. Регулярно смотреть, что туда попадает.

Масштабирование

Конкурирующие потребители (Competing Consumers)

Несколько экземпляров читают из одной очереди.

    graph LR
    A[Очередь] --> B[Экземпляр 1]
    A --> C[Экземпляр 2]
    A --> D[Экземпляр 3]
  

Что даёт: Горизонтальное масштабирование обработки. Каждый экземпляр берёт следующее сообщение.

Партиционирование

Очередь разбивается на партиции. Каждая партиция обрабатывается одним потребителем.

    graph LR
    A[Партиция 0] --> B[Потребитель 1]
    C[Партиция 1] --> D[Потребитель 2]
    E[Партиция 2] --> F[Потребитель 3]
  

Что даёт: Параллельная обработка с сохранением порядка внутри партиции.

Пример: Обработка заказа

Схема:

    graph TD
    A[Веб-сайт] -->|создан заказ| B[Брокер]
    B -->|событие| C[Система оплаты]
    B -->|событие| D[Система уведомлений]
    B -->|событие| E[Склад]
    B -->|событие| F[CRM]
  

Что происходит:

  1. Веб-сайт создаёт заказ и отправляет событие в брокера
  2. Брокер рассылает событие всем подписчикам
  3. Каждая система обрабатывает независимо
  4. Если склад временно недоступен — сообщение ждёт в очереди
  5. Если CRM упала — при восстановлении получит все события

Что получаем:

  • Слабая связанность: веб-сайт не знает о CRM, складе, уведомлениях
  • Асинхронность: веб-сайт не ждёт обработки
  • Надёжность: сообщения не теряются

Брокер vs Точка-точка

ХарактеристикаТочка-точкаЧерез брокер
СвязанностьВысокаяНизкая
МасштабированиеТрудноЛегко
БуферизацияНетДа
НадёжностьНизкаяВысокая
ЗадержкаНизкаяНемного выше
СложностьНизкаяСредняя
Новые системыНужно подключать ко всемПросто подписать на топик
Изменение APIЛомает всехЛомает только отправителя и получателя

Когда выбирать брокер

УсловиеПочему
Систем >5Иначе спагетти интеграции
Часто меняются APIБрокер изолирует изменения
Нужна надёжностьБуферизация, повторы, DLQ
Асинхронность допустимаОтправитель не ждёт ответа
Нужно масштабировать обработкуКонкурирующие потребители
Одно событие — много получателейPub-Sub

Когда точка-точка всё ещё лучше

УсловиеПочему
Мало систем (2-5)Брокер — оверхед
Низкая задержка критичнаПрямой вызов быстрее
Синхронный ответ нужен“Заплатил — сразу узнал результат”
Проект небольшойБрокер — избыточная сложность

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

Ошибка 1: Брокер как серебряная пуля

Внедрили брокер, но продолжают делать синхронные вызовы через него.

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

Ошибка 2: Игнорирование идемпотентности

Брокер гарантирует at-least-once, получатель не обрабатывает дубликаты.

Решение: Сделать обработку идемпотентной (по idempotency key).

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

Сообщения падают в DLQ, никто не смотрит.

Решение: Алерт при появлении сообщений в DLQ.

Ошибка 4: Неправильный выбор брокера

Выбрали Kafka для сложной маршрутизации (нужен RabbitMQ). Или RabbitMQ для высоких нагрузок (нужна Kafka).

Решение: Изучить сильные стороны брокеров.

Ошибка 5: Порядок сообщений не обеспечен

Отправили “сначала обновление, потом создание”. Получатель получил в другом порядке.

Решение: Использовать партиции или гарантии порядка.

Резюме

  1. Брокер сообщений — центральный посредник, через который системы обмениваются сообщениями.

  2. Модели: очередь (одному получателю), топик (многим получателям).

  3. Плюсы: слабая связанность, асинхронность, буферизация, надёжность, масштабируемость.

  4. Минусы: сложность, дополнительная задержка, инфраструктура.

  5. Режимы доставки: at-most-once, at-least-once, exactly-once.

  6. Dead Letter Queue (DLQ) — очередь для сообщений, которые не удалось обработать.

  7. Когда выбирать брокер: систем >5, нужна надёжность, асинхронность, масштабирование.

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

Вопрос 1 из 4
Что является ключевой идеей интеграции через брокер сообщений?
Чем отличается queue от topic?
Что означает режим доставки at-least-once?
Для чего нужна Dead Letter Queue (DLQ)?

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