Message Queue
August 14, 2023

RabbitMQ vs Apache Kafka: какой брокер сообщений выбрать

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

Учитывая вышеупомянутые риски и высокую конкуренцию, становится очевидно, что значение характеристик будет продолжать расти.

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

RabbitMQ

RabbitMQ — это брокер сообщений, работающий по протоколу AMQP (Advanced Message Queuing Protocol), в основе которого лежит три понятия:

Message (сообщение) – это собственно те самые объекты, передачей и обработкой которых должен заниматься брокер;

Exchange (обменник) – узел, находящийся на входе брокера сообщений, который перенаправляет и распределяет их между очередями.

Queue (очередь) – некие хранилища, куда обменник распределяет сообщения, и откуда впоследствии они будут взяты клиентом (получателем).

Кроме того, стоит отдельно упомянуть такое понятие, как binding – связь (отношение) между обменником и конкретной очередью, параметры которой напрямую влияют на распределение сообщений. С помощью связей указывается, какие типы сообщений будут попадать в очередь.

Помимо вышеописанных понятий, используемых в AMQP, для любого брокера сообщений актуальны такие термины, как producer и consumer – это отправитель и получатель сообщений соответственно. Они не являются частями брокеров, но это неотъемлемая часть всего механизма обмена сообщениями.

Процесс работы RabbitMQ

В начале producer посылает сообщение в exchange (обменник), который, согласно информации в binding (связях) далее передаёт его нужным очередям. К ним, в свою очередь, подключены consumer’ы. Queue (очереди) отправляют им сообщение, и этим, по сути, заканчивается основной механизм работы RabbitMQ.

Основной смысл функционирования данной схемы – маршрутизация и распределение сообщений между нужными отправителями и получателями с помощью настройки binding и выходных подключений очередей.

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

Apache Kafka

Apache Kafka — это распределенный реплицированный журнал фиксации изменений (commit log). В отличие от RabbitMQ, он не имеет чёткого соответствия AMQP, а реализует свой собственный протокол.

Apache Kafka тоже имеет ряд своих ключевых терминов:

Topic (тема) – если проводить аналогию с предыдущим рассмотренным брокером сообщений, то это очередь. Однако здесь есть важное отличие: если очередь в RabbitMQ – это неделимое хранилище сообщений, то topic в Kafka разделён на partitions.

Partition (раздел) – часть очереди, может размещаться на другом сервере.

Offset (сквозной номер) – указатель на последнее прочитанное сообщение в разделе.

Broker (брокер) – объединяет в себе несколько разделов, как правило, из разных тем. Для обеспечения наивысшей стабильности и отказоустойчивости всей системы рекомендуется размещать их на разных физических серверах.

Процесс работы Apache Kafka

Несмотря на то, что Apache Kafka решает по сути ту же задачу, что и RabbitMQ, под капотом он устроен совсем иначе.

В Kafka сообщения от producer’ов поступают напрямую в topic’и (аналог очередей из RabbitMQ) и, соответственно, в этой схеме нет надобности использовать промежуточный узел, как, например, ранее упомянутый Exchange. Если посмотреть чуть глубже, то мы увидим, что сообщения поступают в конкретную(ые) partition(s) нужного(ых) topic(s). Они, в свою очередь, распределены по брокерам, которые, как правило, находятся на разных физических серверах, что даёт высокую отказоустойчивость системы. В обеспечении этого также важную роль играет механизм репликации. Он позволяет не потерять сообщения из partitions, хранящихся на недоступном на данный момент сервере за счёт ведения их реплик на других брокерах и возможности автоматического переключения на них в случае неполадок.

Ключевой момент — вышеперечисленные особенности использования Kafka позволяют строить на ней распределенные системы с высокой отказоустойчивостью.

Одним из ключевых отличий от RabbitMQ является то, что в Kafka consumer контролирует процесс получения сообщений. Именно он подключается к partition и считывает оттуда сообщения. С этим связана и другая важная особенность – один consumer может быть связан только с одним partition и наоборот. Благодаря этому возможно осуществить механизм отслеживания тех сообщений, которые уже были прочитаны consumer’ом, и тех, что ещё ждут своей очереди. Для этого используется Offset. По сути это метка, которая указывает где было остановлено чтение сообщений consumer’om из partition (можно назвать это смещением). Кроме того, Offset можно сдвигать, что позволяет перечитывать сообщения заново в случае необходимости.

Выводы

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