Зачем вообще нужен брокер сообщений
Представь: у тебя есть интернет-магазин. Пользователь нажимает «Оформить заказ» — и в этот момент нужно сделать несколько вещей одновременно: снять деньги, уведомить склад, отправить письмо, обновить CRM, пересчитать остатки. Если делать всё это последовательно в одном HTTP-запросе, пользователь будет ждать секунды три-четыре. А если один из сервисов упадёт — заказ вообще не оформится.
Брокер сообщений решает это иначе: сервис публикует событие «заказ создан» и сразу возвращает ответ пользователю. Остальные сервисы подписаны на это событие и обрабатывают его независимо друг от друга. Склад получил — хорошо. CRM упала — событие полежит в очереди и дойдёт, когда CRM поднимется.
Это и есть суть event-driven архитектуры: компоненты системы общаются через события, а не через прямые вызовы друг к другу. Брокер — посредник, который принимает события от одних и раздаёт другим.
Три главных игрока на рынке — Apache Kafka, RabbitMQ и Redis Streams. На первый взгляд делают похожее. На практике — разные инструменты для разных задач.
Apache Kafka: журнал событий для серьёзных нагрузок
Kafka — это не просто очередь, это распределённый журнал событий. Главное отличие от классических брокеров: сообщения не удаляются после того, как их прочитали. Они остаются в топике столько, сколько ты настроишь — хоть неделю, хоть год.
Почему это важно? Допустим, ты строишь аналитическую систему. Новый микросервис подключился через месяц после запуска — он может прочитать все события за этот месяц с самого начала. Или нашли баг в логике обработки — идёшь в Kafka, берёшь события за нужный период и переигрываешь их заново с исправленным кодом. Это называется event sourcing, и без append-only лога так не сделаешь.
Kafka без проблем держит сотни тысяч сообщений в секунду. Крупные компании гоняют через неё миллиарды событий в день. Горизонтальное масштабирование встроено в архитектуру: добавляешь брокеры и партиции — пропускная способность растёт.
Партиции и группы консьюмеров — ключевые концепции. Топик разбивается на партиции, каждую из которых читает один консьюмер из группы. Хочешь больше параллелизма — добавляй партиции. Порядок событий гарантирован только внутри одной партиции, и это нужно учитывать при проектировании.
Слабые стороны Kafka — порог входа и инфраструктурный вес. Нужен ZooKeeper или KRaft (начиная с Kafka 3.x), нужно понять репликацию, retention policy, consumer lag. Для небольшого проекта это может быть избыточно — как взять грузовик, чтобы перевезти диван.
Когда выбирать Kafka: финтех, аналитика в реальном времени, логирование событий, стриминг данных между микросервисами при высокой нагрузке, системы с требованием переигрывать события.
RabbitMQ: гибкая маршрутизация и надёжность из коробки
RabbitMQ — более классический брокер с очередями и обменниками (exchanges). Сообщение приходит в обменник, тот по правилам раскидывает его по очередям, консьюмеры читают из очередей и подтверждают обработку.
Главная сила RabbitMQ — богатая система маршрутизации. Direct exchange направляет сообщение в конкретную очередь. Fanout рассылает всем подписчикам одновременно. Topic позволяет фильтровать по шаблонам. Headers маршрутизирует по произвольным атрибутам сообщения. Это очень гибко — можно настроить сложную логику без дополнительного кода в консьюмере.
Acknowledgement работает из коробки: пока консьюмер не подтвердил обработку, сообщение считается не доставленным. Если консьюмер упал — сообщение вернётся другому консьюмеру в группе. Dead letter queue автоматически забирает сообщения, которые не удалось обработать после N попыток.
Живой пример: сервис уведомлений. Пришёл заказ — нужно отправить email VIP-клиентам, SMS обычным, push в мобильное приложение. Создаёшь topic exchange с routing key по типу клиента — и каждая очередь получает только свои сообщения. Чисто, без ветвления в коде.
Ещё одна киллер-фича — priority queues. Можно задать приоритет сообщению, и брокер обработает важные первыми. В Kafka такого нет.
Слабые стороны: по умолчанию сообщения удаляются после прочтения — истории нет. Для переигрывания событий нужно хранить их отдельно. Производительность ниже, чем у Kafka, но для большинства задач её хватает — 50-100k сообщений в секунду на нормальном железе.
Когда выбирать RabbitMQ: задачи с ветвлением маршрутизации, важна гарантия «хотя бы одна доставка», нужна приоритизация, нужны dead letter queues, команда не хочет разбираться с Kafka.
Redis Streams: быстро и без лишнего веса
Redis Streams появился в Redis 5.0 и сочетает идеи Kafka с простотой Redis. Если Redis уже есть в инфраструктуре — ты фактически получаешь брокер почти бесплатно.
Структура данных — append-only лог с уникальными ID вида 1700000000000-0 (timestamp + порядковый номер). Consumer groups работают примерно как в Kafka: каждое сообщение обрабатывается одним консьюмером из группы. Pending Entries List отслеживает, какие сообщения взяты в работу, но ещё не подтверждены.
Команды простые: XADD добавляет сообщение, XREADGROUP читает с подтверждением, XACK подтверждает обработку. Всё это нативные Redis-команды, документация понятная.
Ограничения важно понять сразу: Redis хранит данные в памяти. Без настроенной персистентности (AOF или RDB) при рестарте потеряешь очередь. Даже с AOF — это не то же самое, что дисковое хранилище Kafka с репликацией. Для критически важных данных — осторожно и с пониманием.
Горизонтальное масштабирование сложнее, чем у Kafka. Для огромных объёмов Redis Streams — не лучший выбор.
Когда выбирать Redis Streams: уже используешь Redis и не хочешь новый сервис в инфраструктуре, небольшие объёмы, быстрые прототипы, временные задачи вроде отслеживания действий пользователя в сессии.
Сравнение на одном примере
Система обработки заказов: принять оплату → уведомить склад → списать бонусы → отправить чек → записать в аналитику. Нагрузка до 5000 заказов в час в пиковые дни. Аналитике нужна история за полгода.
Kafka — для аналитики и журнала событий. Все события пишем в Kafka, аналитические сервисы читают оттуда сколько угодно раз, можно переигрывать за любой период.
RabbitMQ — для оперативной обработки. Уведомление склада, списание бонусов, отправка чека — всё через RabbitMQ с acknowledgement и dead letter queue на случай сбоев.
Redis Streams — для быстрых временных событий. Лог запросов к API внутри сессии, уведомления между сервисами без критических требований к надёжности.
Это не теория — реальные системы часто используют несколько брокеров для разных задач. Это нормально.
Сколько это стоит в инфраструктуре
Managed-решения в облаке:
- Confluent Cloud (Kafka): от $0.10 за GB обработанных данных плюс хранение
- CloudAMQP (RabbitMQ): бесплатный тариф до 1 млн сообщений в месяц, платные от $19 в месяц
- Redis Cloud: бесплатный тариф 30MB, платные от $7 в месяц
Если разворачиваешь сам на VPS: Kafka с KRaft или ZooKeeper потребует минимум 4GB RAM (лучше 8GB), RabbitMQ нормально живёт на 1-2GB, Redis — ещё меньше.
Для небольших проектов самостоятельная установка RabbitMQ или Redis Streams на существующем сервере — вполне рабочий вариант. Kafka самостоятельно имеет смысл только если есть опыт или готовность потратить время на настройку.
Как это связано с API
REST API и event-driven архитектура — не конкуренты, а партнёры. REST хорошо работает для запрос-ответ: клиент спрашивает — сервер отвечает. Но когда клиенту нужно узнать, что что-то произошло, опросы каждые несколько секунд — плохое решение: нагрузка на сервер, задержка, лишний код.
Брокеры сообщений закрывают эту дыру: бэкенд публикует событие, фронтенд получает уведомление через WebSocket или Server-Sent Events. Или сервисы внутри системы обмениваются событиями без прямых HTTP-вызовов.
Это снижает связность: сервисы не знают друг о друге, они только знают о событиях. Упал один — остальные продолжают работать. Добавить новый подписчик на событие — не нужно трогать источник.
Если планируешь интеграцию нескольких сервисов или строишь систему микросервисов — рано или поздно дойдёшь до задачи, где брокер сообщений окажется правильным инструментом. В REEXY мы помогаем разобраться с такими интеграциями — от выбора инструментов до конкретной реализации.
Частые ошибки
Kafka везде. Kafka мощная, но требует ресурсов и экспертизы. Если у тебя 500 сообщений в час — Kafka просто добавит сложности без выгоды. Начни с RabbitMQ или Redis Streams.
Игнорировать acknowledgement. В RabbitMQ консьюмер должен подтверждать обработку. Если не настроить — при авто-ack сообщения теряются при сбое, при no-ack очередь накапливается бесконечно.
Отсутствие мониторинга. Очереди имеют свойство расти, если консьюмер тормозит или падает. Без метрик по consumer lag и глубине очереди узнаешь об этом, когда сервер закончит память. У всех трёх инструментов есть встроенные метрики — подключай к Prometheus с первого дня.
Dead letter queue как мусорка. Dead letter queue — не место для забытых сообщений, это сигнал о проблеме. Настрой алерты на её наполнение и разбирай причины, а не игнорируй.
Не думать о порядке. В Kafka порядок гарантирован только внутри партиции. Если несколько партиций и важен глобальный порядок событий — это нужно проектировать явно: либо одна партиция (потеря масштабируемости), либо порядок обеспечивается на уровне приложения.
Тестировать только happy path. Проверь, что происходит, когда консьюмер падает в середине обработки, когда брокер недоступен, когда сообщение невалидно. Именно в этих сценариях event-driven архитектура либо спасает, либо подводит — в зависимости от того, насколько хорошо ты её настроил.
Как выбрать
Три вопроса, которые помогут определиться:
Нужна ли история событий и возможность их переигрывать? Да — смотри на Kafka или Redis Streams. Нет — RabbitMQ достаточно.
Какая нагрузка? До 20-30k сообщений в секунду — RabbitMQ или Redis Streams справятся. Выше и с масштабированием — Kafka.
Уже есть Redis в проекте и объёмы небольшие? Redis Streams — самый быстрый старт без новых зависимостей.
Не бойся начать с простого. RabbitMQ на одном узле для MVP — это нормальное решение. Перейти на Kafka потом, когда нагрузка вырастет, проще, чем сразу разбираться с Kafka без опыта.