Алексей Меленчук
вся записка
узел 03 · Обмен
дата
объём 5 мин чтения

Kafka или RabbitMQ: журнал против брокера

В чём разница между Kafka и RabbitMQ, почему вопрос «что быстрее» поставлен неверно и по какому признаку выбирать. Плюс третий вариант, который часто лучше обоих.

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

Сравнение обычно начинают с производительности, и это первая ошибка. Kafka и RabbitMQ отличаются не скоростью, а тем, что вообще происходит с сообщением.

Две модели

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

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

Из этого различия следует всё остальное, и различие это не про скорость.

Что даёт журнал

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

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

Порядок внутри партиции. Гарантируется. Это важно, когда события по одной сущности обязаны примениться в том порядке, в каком произошли.

Цена: партиция — единица параллелизма. Больше потребителей в группе, чем партиций, — лишние простаивают. Число партиций планируется заранее и увеличивается неудобно.

Что даёт брокер

Маршрутизация. Обменники по типу, по образцу ключа, широковещательные. Правило «эти сообщения в очередь A, те в B, а вот эти в обе» описывается конфигурацией, а не кодом потребителя.

Подтверждение по каждому сообщению. Обработчик упал на середине — сообщение вернулось в очередь и досталось другому. В журнале единица учёта — смещение, и «не смог обработать вот это конкретное, но следующее обработал» выражается тяжелее.

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

Приоритеты и срок жизни. Есть.

Цена: подтверждённое сообщение исчезло. Перечитать нечего.

Признак выбора

Один вопрос: сообщение — это задание или событие?

Задание адресовано исполнителю, выполняется один раз и после этого не нужно. «Отправить письмо», «сжать картинку», «пересчитать отчёт». Это очередь, и это RabbitMQ.

Событие — запись о том, что произошло. Оно интересно нескольким подписчикам, и может стать интересно шестому через полгода. «Заказ оплачен», «пользователь зарегистрировался». Это журнал, и это Kafka.

Спор «что быстрее» бессмыслен, потому что при типичных для веб-бэкенда объёмах оба справляются с запасом, а разница проявляется на порядках, которых у большинства проектов нет.

Механика, которая определяет пределы

Три детали, из которых складываются реальные ограничения.

Группы потребителей и партиции. В Kafka партиция закреплена за одним потребителем группы. Партиций восемь — параллелизм не выше восьми, девятый потребитель простаивает. Увеличить число партиций можно, уменьшить нельзя, и увеличение ломает соответствие ключа партиции, а значит и порядок.

Отсюда: число партиций — решение, которое принимают заранее и меняют неохотно. В RabbitMQ такого ограничения нет: потребители тянут из очереди, сколько бы их ни было.

Что именно упорядочено. Kafka гарантирует порядок внутри партиции, а не внутри топика. Сообщения по одному ключу попадают в одну партицию и приходят по порядку; между ключами порядка нет. Если порядок нужен по сущности — ключом должен быть её идентификатор.

RabbitMQ гарантирует порядок в очереди при одном потребителе. Добавили второго ради скорости — порядок кончился.

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

Эксплуатационная разница

Она весомее функциональной и почти не обсуждается.

Kafka — распределённая система с координацией, репликацией и перебалансировкой групп. Её надо мониторить по отставанию потребителей, следить за размером диска, понимать, что происходит при перебалансировке и почему потребитель встал.

RabbitMQ на одном узле ставится и работает. Кластер сложнее, но и он проще, чем кластер Kafka.

Если у вас нет команды, которая уже умеет эксплуатировать Kafka, это существенная часть цены — и она платится не в момент выбора, а в первую ночь, когда что-то встало.

Третий вариант, о котором забывают

Если поток небольшой, потребитель один и события не нужно перечитывать — очередь в PostgreSQL обыгрывает оба варианта.

SELECT * FROM jobs
 WHERE status = 'pending'
 ORDER BY created_at
 FOR UPDATE SKIP LOCKED
 LIMIT 10;

SKIP LOCKED пропускает строки, заблокированные другими читателями, — то есть даёт конкурентную выборку заданий без внешнего брокера.

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

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

Что не решает ни один из них

Ни Kafka, ни RabbitMQ не дают однократной обработки. Оба гарантируют доставку «хотя бы раз», и дубликаты лечатся идемпотентностью получателя — разобрано отдельно.

Ни один не спасёт от лавины повторов, если политика повтора настроена без джиттера и бюджета.

Выбор брокера — примерно десятая по важности задача в списке того, что делает обмен сообщениями надёжным. Первые девять — про ваш код.

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