RabbitMQ или Kafka: что выбрать

Два инструмента, которые постоянно ставят рядом, хотя они решают разные задачи — разбираемся, в чём настоящая разница.

RabbitMQ — брокер очередей: сообщение доставляется потребителю и после подтверждения удаляется. Kafka — распределённый лог: события пишутся в файл-подобную структуру, хранятся заданный срок и читаются любым числом потребителей столько раз, сколько нужно.

Главное различие: кто помнит, что прочитано

Если запомнить из урока одну вещь — пусть это будет она. В RabbitMQ состояние чтения хранит брокер. Он знает, какое сообщение кому отдано и по какому пришёл ack; подтверждённое сообщение из очереди исчезает. Очередь — это «список дел», который постепенно пустеет.

В Kafka состояние чтения хранит потребитель (в виде offset — номера позиции в логе). Само сообщение никуда не девается: оно лежит в партиции, пока не истечёт retention (например, 7 дней). Прочитать его можно повторно — достаточно отмотать offset назад. Лог — это «журнал событий», который не пустеет от чтения.

Отсюда растут все остальные отличия. Kafka умеет реплей (перечитать историю с начала) — потому что она ничего не удаляет. RabbitMQ реплей не умеет — потому что удаляет. Зато RabbitMQ умеет сложную маршрутизацию на стороне брокера и точечные подтверждения каждого сообщения — потому что он и так следит за судьбой каждого из них.

RabbitMQ: маршрутизация как суперсила

Издатель в RabbitMQ публикует не в очередь, а в exchange, и брокер сам решает, куда положить копии. Правила описываются привязками:

import pika

connection = pika.BlockingConnection(pika.ConnectionParameters("localhost"))
channel = connection.channel()

# topic-обменник умеет маршрутизировать по шаблону ключа
channel.exchange_declare(exchange="orders", exchange_type="topic", durable=True)

channel.queue_declare(queue="billing", durable=True)
channel.queue_declare(queue="warehouse", durable=True)
channel.queue_declare(queue="audit", durable=True)

# бухгалтерии — только оплаченные заказы
channel.queue_bind(queue="billing", exchange="orders", routing_key="order.*.paid")
# складу — только заказы из московского региона
channel.queue_bind(queue="warehouse", exchange="orders", routing_key="order.msk.*")
# аудиту — вообще всё
channel.queue_bind(queue="audit", exchange="orders", routing_key="order.#")

channel.basic_publish(exchange="orders", routing_key="order.msk.paid", body=b"{}")
# это сообщение попадёт сразу в три очереди: billing, warehouse и audit

Обратите внимание: издатель не знает ни про billing, ни про warehouse. Он просто сообщает ключ order.msk.paid. Вся логика «кому это интересно» живёт в брокере и меняется без единой строчки кода — хоть из веб-панели. В Kafka такой логики нет: продюсер пишет в конкретный топик, и разбирать «моё/не моё» потребитель обязан сам.

Второй козырь — очередь как список задач с честной конкуренцией. Запустили десять воркеров на одну очередь — RabbitMQ раздаёт им сообщения по одному, кто освободился, тот и получил следующее. Медленный воркер просто возьмёт меньше задач. В Kafka параллелизм жёстко ограничен числом партиций: 3 партиции — максимум 3 активных потребителя в группе, четвёртый будет простаивать.

Kafka: лог, который помнит всё

from kafka import KafkaConsumer

consumer = KafkaConsumer(
    "user-events",
    bootstrap_servers="localhost:9092",
    group_id="analytics-v2",       # новая группа читает топик с самого начала
    auto_offset_reset="earliest",  # ...потому что offset у неё ещё не сохранён
)

for msg in consumer:
    print(msg.partition, msg.offset, msg.value)

Вот сценарий, ради которого выбирают Kafka. Аналитики нашли баг в расчёте воронки и переписали агрегатор. Им нужно пересчитать метрики за последние полгода. С Kafka это одна строчка: новая consumer group, auto_offset_reset="earliest", и все события за retention-период проезжают через новый код заново. Данные никуда не делись — они лежат в логе.

С RabbitMQ этот сценарий невозможен в принципе: события за полгода давно подтверждены и удалены. Максимум, что у вас есть, — то, что вы сами предусмотрительно сложили в базу или в S3.

Второй сильный ход Kafka — пропускная способность. Она пишет сообщения последовательно в файл и отдаёт потребителям пачками, почти не тратя CPU. Сотни тысяч событий в секунду на скромном кластере — рабочая цифра. RabbitMQ, который для каждого сообщения ведёт учёт доставки и ack, живёт в другом порядке величин: десятки тысяч сообщений в секунду на узел — уже хороший результат. Для 99% бизнес-задач этого хватает с огромным запасом, но кликстрим на 300 тысяч событий в секунду в RabbitMQ пихать не стоит.

Честное сравнение

КритерийRabbitMQKafka
МодельОчередь: прочитал и подтвердил — сообщение удаленоЛог: сообщение живёт весь retention, чтение его не удаляет
Кто помнит позицию чтенияБрокер (per-message ack)Потребитель (offset)
Перечитать историюНельзяДа, это штатный сценарий
МаршрутизацияБогатая: direct / topic / fanout / headers, привязки на брокереНет: продюсер пишет в топик, фильтрует потребитель
Параллелизм потребителейСколько угодно воркеров на одну очередьНе больше числа партиций в группе
Порядок сообщенийВ пределах очереди при одном потребителеСтрогий в пределах партиции (ключ → партиция)
Приоритеты, TTL, отложенная доставкаЕсть из коробкиНет, надо городить самому
Пропускная способностьДесятки тысяч сообщений/с на узелСотни тысяч и выше
Порог входа в эксплуатациюНизкий: один контейнер, веб-панельВыше: кластер, партиции, ребалансировки, мониторинг лага

Как это работает: три вопроса вместо холивара

На собеседовании и в реальном проектировании выбор сводится к трём вопросам.

1. Это задача или факт?

«Отправь письмо пользователю 42», «сделай превью для видео», «пересчитай баланс» — это задача (command). У неё один исполнитель, её надо выполнить один раз и подтвердить. Это RabbitMQ.

«Пользователь 42 зарегистрировался», «товар добавлен в корзину», «страница просмотрена» — это факт (event). Он уже случился, слушателей может быть сколько угодно, и завтра появится ещё один. Это скорее Kafka — особенно если фактов много и их захотят перечитывать.

2. Понадобится ли перечитать историю?

Если ответ «да» или «наверное, аналитики попросят» — это сильный аргумент за Kafka. Если события живут ровно до обработки и никому потом не нужны — RabbitMQ проще во всём.

3. Какой у вас порядок нагрузки?

Тысячи сообщений в секунду — оба справятся, выбирайте по удобству. Сотни тысяч — RabbitMQ будет больно. Десятки сообщений в минуту — Kafka будет избыточным кластером, который вы будете обслуживать ради трёх писем в час.

И главное: это не «или-или». Во многих компаниях спокойно живут оба: Kafka собирает поток событий и кормит аналитику, а RabbitMQ разносит фоновые задачи между сервисами. Каждый занят тем, для чего создан.

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

  • Брать Kafka «потому что все берут». Кластер Kafka — это ZooKeeper или KRaft, партиции, ребалансировки, мониторинг consumer lag и человек, который во всём этом разбирается. Если у вас 500 писем в день, RabbitMQ в одном контейнере закроет задачу за вечер.
  • Ждать от RabbitMQ реплея. «А давайте перечитаем очередь за прошлый месяц» — так нельзя. Подтверждённые сообщения удалены навсегда. Нужна история — пишите её в базу отдельно или берите лог.
  • Ждать от Kafka маршрутизации. Попытки сделать «топик на каждый тип события с хитрым фильтром» кончаются сотнями топиков и болью. Фильтрация — работа потребителя.
  • Забыть про партиции при выборе Kafka. Создали топик с одной партицией — получили ровно одного работающего потребителя в группе, сколько бы вы их ни запустили. Число партиций легко увеличить, но нельзя уменьшить.
  • Сравнивать по бенчмаркам вместо задач. «Kafka быстрее» — правда, но бессмысленная, если вам нужно 200 сообщений в секунду и приоритетная очередь.

Итоги

  • RabbitMQ — очередь: брокер помнит доставку, сообщение исчезает после ack. Kafka — лог: позицию помнит потребитель, сообщение живёт весь retention.
  • RabbitMQ силён в маршрутизации (topic/fanout/direct), приоритетах, TTL и в раздаче задач конкурирующим воркерам.
  • Kafka сильна в потоке событий, огромной пропускной способности и реплее истории.
  • Эвристика: задача с исполнителем → RabbitMQ, факт для многих подписчиков с возможным перечитыванием → Kafka.
  • Оба инструмента прекрасно уживаются в одной системе — выбор делается на уровне конкретного потока данных, а не всей компании.
Проверьте себя
1. Аналитики переписали агрегатор и хотят пересчитать метрики по всем событиям за последние 30 дней. Какой инструмент делает это штатно?
ARabbitMQ: достаточно перепривязать очередь к обменнику
BKafka: новая consumer group читает лог с начала (auto_offset_reset=earliest)
CОба одинаково — это стандартная функция любого брокера
DНи один: историю всегда приходится хранить в отдельной базе
2. В чём принципиальное преимущество RabbitMQ перед Kafka?
AОн хранит сообщения дольше и позволяет отматывать offset назад
BОн даёт заведомо большую пропускную способность на одном узле
CОн умеет маршрутизацию на стороне брокера (topic/fanout/direct) и раздаёт задачи любому числу конкурирующих воркеров
DОн гарантирует строгий глобальный порядок всех сообщений в системе