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

Какие бывают виды общения?

Давайте разберёмся, какие виды общения нас окружают. Самый распространённый вариант — любой диалог. Кто-то N обращается к кому-то Y и высказывает ему мнение, ждёт ответа или обратную связь.

Пример, общение по телефону:

Или всё то же самое, только N, транслируя сообщение Y, не ждёт от него ответа. Да-да, бывают такие люди, которые только привыкли высказывать собственное мнение. Также, кстати, работают рекламные рассылки или push-уведомления на телефоне.

Работа системы оповещения:

Есть варианты общения не напрямую, а через посредника. Например, N просит X запомнить сообщение и передать всем его друзьям. При этом N не знает, кто входит в круг друзей X. X передаёт сообщение всем друзьям — C, D, E.

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

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

Паттерны обмена информации

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

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

  • Request-Response (Запрос-Ответ);

  • One-Way (Односторонний) или Fire and Forget (Отправил и забыл);

  • Publish-Subscribe (Публикация-Подписка) или сокращённо Pub-Sub;

  • Point-to-Point (Точка-Точка).

В интернете Request-Response — это работа HTTP: клиент выполняет запрос на сервер, ждёт и получает ответ. One-Way, когда приложение по сети отправляет UDP (User Datagram Protocol) пакет на сервер без ожидания ответа. Последние два варианта связаны с брокерами сообщений, но о них чуть позже.

Часто в рамках взаимодействия приложения используют паттерн Request-Response. Программы общаются напрямую синхронно друг с другом. У такого взаимодействия есть особенности:

  • отправителю нужно знать адрес получателя;

  • получатель должен быть доступен в момент вызова;

  • из-за сбоя отправитель может никогда не дождаться ответа;

  • отправитель блокируется в ожидании ответа.

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

В паттернах Pub-Sub и Point-to-Point происходит асинхронное общение через посредника. При реализации таких паттернов у программ появляются возможности:

  • осуществлять асинхронный обмен данными (отправитель не блокируется);

  • отделять отправителя от получателя (отправитель ничего не знает о получателе);

  • выполнять отложенную обработку сообщений. Получателю не нужно быть постоянно активным, можно читать сообщения в удобное время;

  • делегировать ответственность за маршрутизацию и доставку сообщений третьей стороне;

  • легко интегрироваться с системами, использующими различные платформы, языки и протоколы связи.

Так кто такие брокеры?

Итак, на прошлых картинках под буквой X прятался брокер сообщений (Message Broker).

Брокер сообщений — это программная система полностью или частично реализующая паттерны Pub-Sub и Point-to-Point. Взаимодействие программ через брокер упрощает процесс разработки. Нет необходимости в каждом сервисе реализовывать механизмы доставки, маршрутизации, хранения сообщений — всем этим занимается «посредник». Общение через «посредника» помогает навести порядок и внести ясность в потоки данных, а значит, упростить разработку и снизить вероятность появление ошибок.

Использование брокера оправдано, если:

  • существуют задачи, выполнение которых требует много времени и ресурсов;

  • не нужен немедленный результат;

  • необходима координация работы большого количества сервисов (событийная модель общения);

  • требуется повысить масштабируемость и отказоустойчивость системы.

Гарантия доставки

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

  • At most once (Не более одного раза)

    Самый простой вариант — отправка в стиле Fire and Forget (Отправил и забыл). Большая часть сообщений доходит до получателя, но часть теряется из-за сбоев.

  • At least once (Хотя бы один раз)

    Чтобы все данные достигли цели, могут предприниматься повторные отправки. Хотя бы одна попытка будет успешной. В таком случае сообщения не теряются, но могут дублироваться.

    Обычно реализуется через механизм подтверждений (ACK, acknowledgment). Сообщение повторяется, если не получено подтверждение о доставке. Возможны дубли, если подтверждение потерялось или не было отправлено из-за сбоя.

  • Exactly once (Строго один раз)

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

Очередь и Топик

Брокер, реализующий шаблон Point-to-Point, ассоциируется с термином Queue (Очередь). Сообщения отправителя попадают в очередь, получатель извлекает сообщения из очереди. После извлечения сообщение становится больше никому не доступными. Данные в очереди хранятся, пока они не будут прочитаны или не истечёт срок их действия.

В Pub-Sub ассоциируется с темой, топиком (Topic). Сообщения попадают в топик. Система распределяет каждое сообщение между всеми подписчиками топика (Broadcast, вещание). Сообщения могут храниться в топике, до тех пор, пока это необходимо для распространения данных между всеми подписчиками.

Разнообразие брокеров в природе

Существует множество программных реализаций брокеров сообщений. Одни из самых известные:

Каждая из реализаций может отличаться по характеристикам:

  • масштабируемость, пропускная способность;

  • отказоустойчивость, возможность восстановления данных в результате сбоя;

  • кластеризация;

  • поддержка моделей Pub-Sub и Point-to-Point;

  • гарантия доставки сообщений;

  • упорядоченная доставка сообщений;

  • контроль доступа;

  • открытость кода;

  • поддерживаемые платформы.

Например, в программных решениях «Иннотех» активно используются, ставшие де-факто стандартом, брокеры сообщений Kafka и RabbitMQ. У этих брокеров есть определённые отличия и особенности работы. Разберём их в качестве примера для понимания специфики принципов работы.

«Умный брокер, тупой потребитель»

RabbitMQ традиционный брокер сообщений с открытым исходным кодом, работающий как автономно, так и в составе кластера. Поддерживает обе модели Pub-Sub и Point-to-Point, протоколы AMQP, MQTT, STOMP и другие. Реализованы гарантии доставки сообщений At most once и At least once.

В случае At most once получается большая пропускная способность, так как данные обрабатываются в быстрой оперативной памяти. At least once надёжный в плане доставки, но менее скоростной в плане передачи данных вариант, потому что используется механизм подтверждений и запись на диск.

В упрощённом виде принципы работы RabbitMQ можно представить так: приложение-отправитель (Publisher) публикует сообщения в брокер, ссылаясь на его внутреннюю сущность Exchange (Обменник). Обменник в зависимости от типа и настроек перенаправляет сообщения в одну или более связанных с ним очередей (Queue). Приложения-подписчики (Consumer) держат постоянное TCP соединение с RabbitMQ и ждут сообщения из заданной очереди. Брокер отправляет (push), распределяет сообщения между подписчиками. Если у очереди несколько подписчиков, сообщения между ними распределяются равномерно. Если сообщение успешно обработано подписчиком, оно удаляется из очереди.

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

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

«Тупой брокер, умный потребитель»

Apache Kafka программный Pub-Sub брокер с открытым исходным кодом. Помимо гарантий доставки At most once и At least once, поддерживает Exactly once (Строго один раз). Обычно используется в больших проектах, так как обладает большой пропускной способностью и отказоустойчивостью, превосходит по данным характеристикам RabbitMQ и многие другие брокеры. При этом имеет высокий порог вхождения, требователен к ресурсам.

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

В Kafka отсутствует понятие очереди (Queue), приложения пишут или читают сообщения из партиционированных топиков (Topic). Если просто, то принцип работы такой: приложение-продюсер (Producer) отправляет сообщение в топик брокера, которое записывается в конец одной из его партиций (Partition). По умолчанию для распределения сообщений между партициями топика используется алгоритм Round-Robin. Отправитель может влиять на выбор партиции, передавая вместе с сообщением специальный ключ (Message Key).

Приложения-подписчики (Consumer) читают, вытягивают (pull) сообщения из заданного топика. Для каждого подписчика Kafka запоминает указатель на последнее прочитанное им сообщение (offset). Если приложение падает, то восстановившись может продолжать чтение с прежнего места или перемотать (rewind) offset в прошлое и прочитать данные повторно.

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

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

В RabbitMQ такой проблемы не существует. Брокер проталкивает (push) сообщения подписчикам и поэтому может сам балансировать, распределять данные между подписчиками очереди. С другой стороны, Push-механизм (Одно сообщение за один раз) менее продуктивный по сравнению с Pull в Kafka.

Выбирая между Kafka и RabbitMQ

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

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

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

Комментарии (26)


  1. Barmaglote
    11.11.2022 16:38
    +2

    Эх... если бы все статьи были такими четкими, лаконичными!


  1. Maxim_Evstigneev
    11.11.2022 16:56

    фантастика, здорово "разжевано", но хотелось бы примеров с кодом для наглядности


    1. baldr
      11.11.2022 17:27
      +2

      На хабре уже с десяток статей на эту тему было. Поищите - там и с кодом найдется, думаю.


  1. dejecher
    11.11.2022 18:44
    +1

    Чем различаются Kafka и RabbitMQ: простыми словами

    Хорошая попытка. Но увы - я уже лет пять примерно тоже самое пытаюсь объяснить, и примерно теми-же словами но... в общем плюнул уже...

    а так да - все правильно написано


    1. ryanl
      11.11.2022 19:06

      По крайней мере, хорошая затравка, однозначно


    1. trusted Автор
      12.11.2022 01:09
      +1

      Не думаю, что все попытки объяснений непонятного понятным языком безрезультативны? Если At least once кто то понял то уже хорошо )))


  1. freeg0r
    11.11.2022 19:07
    +1

    Количество партиций в топике зависит от количества его конкурирующих подписчиков

    не корректно, оно не зависит от подписчиков. Вы можете сделать 10 partitions и 1 consumer, а можете наоборот (тогда конечно 9 консьюмеров будут простаивать). В идеальном случае число partitions должно соответствовать числу потребителей.

    Ну очень поверхностно, есть гораздо больше различий, например Кафка более чувствительна к размеру сообщения и времени его обработки в отличие от RabbitMQ, а у последнего есть варианты подписки basic.consume (подписка как в Kafka) и basic.get, который делает только один запрос в queue. В RabbitMQ можно удалять очереди после прочтения сообщения или по timeout, в отличие от Kafka, и т.п.


    1. baldr
      11.11.2022 19:22

      А еще есть Rabbit.Streams



    1. trusted Автор
      12.11.2022 01:00

      Но все же зависимость существует? Если у топика 10 конкурирующих подписчиков то логично создать 10 партиций? В начале предложения надо было добавить слово "Обычно".


      1. Fuud
        12.11.2022 12:00

        Не логично. По крайней мере в общем смысле.

        Если захочется проскалировать, добавив консюмера, то придется добавить и партицию. А это 1) ручная операция, 2) поломает партицирование по ключу (если используется)

        Если завести 15 партиций на 10 консюмеров, то 5 из них будут нагружены в два раза больше чем 5 остальных.

        Может показаться, что надо завести сотню-другую партиций, чтобы примерно распределить нагрузку поровну между изменяемым количеством консюмеров. Но каждая партиция - это минимум 6 открытых файловых дескрипторов на каждой ноде. И большое количество партиций - возможная проблема с Zookeeper.

        Увы, приходится это все учитывать, по возможности, заранее.


  1. ptr128
    12.11.2022 00:23
    +2

    под управлением Apache Zookeeper

    Уже больше года, как под управлением кворума метаданных

    https://issues.apache.org/jira/browse/KAFKA-9119


    1. trusted Автор
      12.11.2022 00:50

      Хорошее замечание, спасибо. Статья относится к начальному уровню поэтому многие подробности были опущены. Иначе пришлось бы углубляться и рассказать и о существовании других альтернатив для Zoo в виде Consul, Atomix, Jocko ...


      1. Fuud
        12.11.2022 12:02

        А Кафка поддерживает другие альтернативы зукиперу, кроме собственного кворума?


    1. freeg0r
      12.11.2022 13:21
      +1

      не так ультимативно, Zookeeper так же и остался в Кафке, а Metadata Quorum, он же KRaft (https://developer.confluent.io/learn/kraft/) добавлен как мод, и as production ready он помечен только в последнем релизе, вышедшем буквально несколько дней назад


  1. mstaoru
    12.11.2022 06:34
    -6

    Простыми словами: Kafka — для работы, RabbitMQ — поиграться.


    1. dyadyaSerezha
      12.11.2022 07:25
      +1

      Совсем не так. Работы бывают разные.


    1. 16tomatotonns
      12.11.2022 10:40

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


      1. mstaoru
        12.11.2022 19:09

        Немного о разных вещах. Какое-то время назад занимался фрилансом в духе "подниму все, что совсем упало", кролик с тенденцией прилечь был в топе. Может быть, сейчас что-то поменялось. Но Кафка для небольших нагрузок тоже работает нормально. Часто проблемы из пп.1 возникают, потому что проектировали все под девизом "ну у нас же не хайлоад". Наверняка мой датасет весьма перекошен, конечно.


  1. dyadyaSerezha
    12.11.2022 07:26

    Все понял, кроме одного - почему отправитель обозначен буквой N? ????


    1. trusted Автор
      12.11.2022 10:45

      N - Ninja


  1. murkin-kot
    12.11.2022 13:13
    +1

    При этом имеет высокий порог вхождения, требователен к ресурсам.

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

    Немного аналогий:

    Кафка - это кольцо, оно вставляется в этот цилиндр.

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


  1. ottonturk
    12.11.2022 17:21

    статья норм для теоретической части, но важный момент: как проектировать такое взаимодействие?
    Я понимаю, что что архвопрос, но то частый вопрос на людом собеседовании/любом месте работы...
    То есть: как выглядит внутри. где можно развернуть поиграться...


  1. foatto
    12.11.2022 21:14

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


  1. manyakRus
    14.11.2022 13:35
    +1

    Самое главное то не написали:

    Kafka - надо её опрашивать 100 раз в секунду - есть что нового ?

    RabbitMQ - сам вызовет функцию CallBack приложения когда придёт новое сообщение, не надо его опрашивать совсем.


    1. ptr128
      14.11.2022 15:50

      Kafka - надо её опрашивать 100 раз в секунду - есть что нового ?

      Если только средствами Kafka - нет. А вот другими средствами обеспечить нотификацию подписчика из публикатора никто не запрещает. Знаю, костыль. Через REST делаю это в исключительных случаях.