Очередь задач: RabbitMQ, Redis Streams или Kafka
Выбор очереди определяет не только скорость доставки задач, но и поведение системы при сбоях, повторах и росте нагрузки. Сравниваем RabbitMQ, Redis Streams и Kafka по маршрутизации, надёжности, порядку сообщений и цене эксплуатации.

Если отправить все фоновые задачи в Redis «потому что он уже есть», система быстро упрётся в повторы, потерю сообщений или неудобное восстановление после сбоя. RabbitMQ лучше решает маршрутизацию и подтверждение обработки, Redis Streams — короткий путь для уже работающего Redis-кластера, а Kafka — потоковую обработку и повторное чтение истории. Ниже — практический способ выбрать вариант, не переплачивая за функции, которые проекту не нужны.
Сначала опишите задачу, а не выбирайте брокер
Очередь задач нужна, когда производитель не должен ждать завершения работы. Веб-приложение принимает заказ, кладёт событие в брокер, а отдельный worker отправляет письмо, пересчитывает отчёт или вызывает внешний сервис.
До сравнения ответьте на пять вопросов:
- Можно ли выполнить задачу повторно без вреда для данных;
- нужно ли сохранять сообщения после обработки и читать их заново;
- важен ли порядок задач для одного пользователя, заказа или устройства;
- нужна ли сложная маршрутизация по типу события;
- какую задержку и количество сообщений система должна выдерживать в пиковый час.
Ключевая договорённость для большинства рабочих систем — at-least-once delivery.* Сообщение не должно исчезнуть до подтверждения обработки, но при падении worker перед подтверждением оно может прийти повторно. Поэтому очередь не отменяет идемпотентность: повторный платёж, повторная отправка письма или второй запуск миграции нужно отдельно предотвращать.
Выбирайте не самую быструю очередь, а ту, чья модель отказа совпадает с ценой ошибки в вашем бизнес-процессе.
Три варианта и их границы
RabbitMQ 4.x: очередь именно для фоновых задач
RabbitMQ строится вокруг обменников, очередей и маршрутизации. Производитель публикует сообщение в exchange, а тот передаёт его в одну или несколько очередей по правилам binding. Worker получает задачу, выполняет её и отправляет подтверждение. Если consumer отключился до подтверждения, сообщение может вернуться в очередь.
Это сильный вариант для задач вроде обработки заказа, генерации PDF, отправки уведомлений и интеграций с внешними API. Нужную работу можно разделить на очереди: например, emails, images и payments. Для срочных задач можно задать отдельный маршрут, а для неуспешных — dead-letter exchange.
Цена гибкости — операционная сложность. Нужно следить за количеством сообщений, глубиной очередей, неподтверждёнными доставками, скоростью consumer и политиками повторов. Ошибочная настройка retry способна создать бесконечный цикл: worker возвращает задачу, она сразу запускается снова и забивает очередь.
Redis Streams 7.x: очередь рядом с уже существующим Redis
Redis Streams хранит записи в потоке с идентификаторами. Consumer groups позволяют распределять записи между worker-процессами, а подтверждённые сообщения исключаются из списка ожидающих обработки. Неподтверждённые записи можно обнаруживать и передавать другому consumer после сбоя.
Этот вариант удобен, если Redis уже используется для кэша, блокировок или быстрых данных, а нагрузка на задачи умеренная. Компонентов меньше, чем в отдельном RabbitMQ-кластере. При этом Streams не превращает Redis в универсальную замену брокеру: retention, память, репликация и восстановление нужно проектировать отдельно.
Частая ошибка — использовать обычный Redis list и считать задачу надёжно сохранённой только потому, что команда чтения блокируется. Для production-очереди важны подтверждение обработки, контроль зависших сообщений и понятная политика удаления старых записей. Streams дают эти примитивы, но не готовую бизнес-логику повторов.
Kafka 3.x: журнал событий, а не простой список задач
Kafka записывает события в разделы топика и сохраняет их в течение заданного периода или до достижения ограничения по объёму. Consumer group читает разделы параллельно, а позиция чтения фиксируется отдельно. После сбоя consumer может продолжить чтение с последней сохранённой позиции или перечитать часть истории.
Kafka подходит, когда одно событие должны независимо получить несколько систем: склад, аналитика, рекомендации и сервис уведомлений. Она также полезна для повторной обработки большого потока и построения конвейеров, где данные проходят через несколько этапов.
Для обычной фоновой задачи Kafka часто избыточна. Сложность появляется в настройке разделов, репликации, балансе consumer group, задержке обработки и очистке топиков. Отложенные повторы, приоритеты и dead-letter-топики обычно приходится проектировать на уровне приложения или отдельного конвейера.
Сравнение по критериям, которые ломают проекты
| Критерий | RabbitMQ 4.x | Redis Streams 7.x | Kafka 3.x |
|---|---|---|---|
| Основной сценарий | Фоновые задачи и маршрутизация | Задачи рядом с Redis | Потоки событий и повторное чтение |
| Подтверждение обработки | Consumer acknowledgements | Подтверждение записи в consumer group | Фиксация позиции чтения |
| Порядок | Внутри конкретной очереди, с оговорками при нескольких consumer | В пределах потока и последовательности чтения | Гарантируется внутри раздела |
| Маршрутизация | Сильная сторона: exchange и binding | Обычно реализуется в приложении | Топики и разделы, сложная маршрутизация не основная функция |
| Повторное чтение истории | Обычно нужно отдельно сохранять результат или событие | Возможно до удаления записей | Одна из центральных возможностей |
| Повторы и отложенная доставка | Нужно спроектировать через TTL, dead-letter или приложение | Нужно реализовать вокруг pending-записей и расписания | Обычно отдельные топики, поля попыток или планировщик |
| Цена эксплуатации | Отдельный брокер и мониторинг | Меньше компонентов, но конкурирует за ресурсы Redis | Самая высокая операционная сложность из трёх |
Таблица не означает, что один механизм гарантирует «ровно один запуск». При сетевом разрыве любой вариант может привести к повторной доставке или повторному чтению. Для побочных эффектов используйте idempotency key, уникальное ограничение в базе или журнал выполненных операций.
Как выбрать вариант по сценарию
Берите RabbitMQ, если задача — именно работа worker
Выбирайте RabbitMQ, когда у вас много типов задач, разные приоритеты, несколько маршрутов и понятный жизненный цикл «получил — обработал — подтвердил». Он особенно уместен для систем, где сообщение должен забрать ровно один из нескольких worker, а не каждый подписчик.
Перед запуском определите максимальное число попыток. После него переносите сообщение в отдельную очередь для разбора, а не возвращайте бесконечно. Настройте prefetch так, чтобы один worker не забирал слишком много тяжёлых задач: точное значение зависит от времени обработки и размера сообщения, его нужно измерить на вашем профиле нагрузки.
Берите Redis Streams, если важны простота и уже оплаченный Redis
Streams разумен для умеренного потока задач, небольшого числа consumer groups и команды, которая не хочет обслуживать отдельный брокер. Он также удобен для короткой цепочки событий, когда задержка невелика, а история нужна ограниченное время.
Заранее задайте срок хранения записей и сценарий восстановления pending-сообщений. Отдельно проверьте, хватит ли памяти с учётом реплик и других ключей Redis. Если Redis уже работает на пределе из-за кэша, очередь будет конкурировать с кэшем за тот же ресурс.
Берите Kafka, если событие должно жить после обработки
Kafka оправдана, когда одно событие читают несколько независимых систем, когда нужен replay или поток стабильно растёт до объёма, при котором специализированный журнал проще масштабировать по разделам. Ключ сообщения помогает удерживать порядок для одного объекта, например заказа, но не создаёт глобальный порядок во всём топике.
Не используйте Kafka только ради «высокой производительности». Если задача — отправить одно письмо и забыть о ней после подтверждения, журнал событий добавит настройки, мониторинг и сценарии очистки, но не решит бизнес-проблему лучше RabbitMQ.
Что ломается первым
- Повторный запуск. Worker падает после записи результата в базу, но до подтверждения. Повторная доставка снова выполняет операцию. Защитите критический шаг ключом идемпотентности и уникальным индексом.
- Бесконечный retry. Внешний API отвечает ошибкой часами, а система бесконечно возвращает одну задачу. Нужны лимит попыток, задержка между ними и отдельный поток для ручной проверки.
- Скрытая потеря порядка. Несколько consumer обрабатывают события одного заказа параллельно. Если порядок критичен, маршрутизируйте такие события в одну последовательность и не ограничивайтесь общей очередью.
- Большие сообщения. В очередь кладут архивы, изображения или полный JSON заказа. Растут задержки, память и время восстановления. Обычно в сообщение кладут идентификатор объекта, а полезные данные хранят отдельно.
- Нет метрики возраста. Размер очереди может быть небольшим, но одна старая задача уже ждёт час. Следите не только за длиной очереди, но и за возрастом самой старой записи, временем обработки и долей повторов.
Как проверить выбор до запуска
Сделайте небольшой нагрузочный стенд на той же версии брокера, которую планируете использовать: RabbitMQ 4.x, Redis 7.x или Kafka 3.x. Возьмите реальные размеры сообщений и время работы worker, а не синтетическую задачу на несколько миллисекунд.
Проверьте четыре сценария: остановка worker после получения, недоступность брокера, всплеск задач и медленный внешний API. Зафиксируйте время от публикации до начала обработки, долю повторов, время восстановления и объём потерянных сообщений. Если измерений ещё нет, не подставляйте чужие цифры: производительность зависит от дисков, сети, настроек подтверждений, размера сообщения и числа consumer.
Отдельно проведите тест восстановления. Одна система может быстро продолжить работу после перезапуска, но долго разбирать неподтверждённые записи. Для бизнеса это разные показатели и разные риски.
Что делать дальше
Начните с контракта сообщения: идентификатор задачи, тип операции, версия схемы, время создания, число попыток и ключ идемпотентности. Затем выберите один критический маршрут и опишите его состояния: опубликовано, получено, выполнено, отложено, отправлено в ручной разбор.
После пилота добавьте дашборд с глубиной очереди, возрастом старой задачи, скоростью обработки, ошибками и количеством повторов. Если система начнёт расти, именно эти показатели покажут, пора ли разделять очереди, увеличивать число consumer или переходить от Redis Streams к отдельному брокеру. Инвалидация кэша и схема транзакционной публикации — отдельные темы, здесь важен только жизненный цикл фоновой задачи.
* At-least-once — доставка «как минимум один раз»: сообщение не удаляют до подтверждения, поэтому после сбоя оно может быть обработано повторно.
Задачи: математика, физика, химия: Разбор задачи по шагам с проверкой и похожей задачей
Спросить за 10 ₽Источники: RabbitMQ Documentation: Queues, Apache Kafka Documentation: Introduction
Частые вопросы
Что выбрать для отправки писем, отчётов и фоновых задач?
Можно ли считать RabbitMQ, Redis Streams или Kafka очередью с ровно одной обработкой?
Что будет, если worker упадёт после получения сообщения?
Подойдёт ли Kafka для одной очереди фоновых задач?
Что делать, если у меня другая версия брокера?
Как понять, что выбранная очередь не справляется?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.