RabbitMQ и отношения между каналом и соединением

176

Клиент RabbitMQ Java имеет следующие понятия:

  • Connection - соединение с экземпляром сервера RabbitMQ
  • Channel - ???
  • Пул потребительских потоков - пул потоков, которые принимают сообщения из очередей сервера RabbitMQ
  • Очередь - структура, которая содержит сообщения в порядке FIFO

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

  1. Я до сих пор не совсем уверен, что это Channel, кроме того факта, что это структура, из которой вы публикуете и используете, и что она создается из открытого соединения. Если бы кто-то мог объяснить мне, что представляет собой «Канал», это могло бы помочь прояснить некоторые вещи.
  2. Какая связь между каналом и очередью? Можно ли использовать один и тот же канал для связи с несколькими очередями, или он должен быть 1: 1?
  3. Какова связь между очередью и потребительским пулом? Могут ли несколько потребителей быть подписаны на одну и ту же очередь? Можно ли использовать несколько очередей одним и тем же потребителем? Или это соотношение 1: 1?

Заранее спасибо за любую помощь здесь!


источник
Ответы на этот вопрос побудили меня сообщить об этой проблеме клиенту golang, а не задавать вопрос здесь.
Брюс Адамс
Канал - это логическая концепция, используемая для мультиплексирования одного физического TCP-соединения между клиентом и узлом. Номер канала включен в заголовок сообщения кадра AMQP.
ymas

Ответы:

196
  1. A Connectionпредставляет собой реальное TCP-соединение с брокером сообщений, тогда как a Channelпредставляет собой виртуальное соединение (AMQP-соединение) внутри него. Таким образом, вы можете использовать столько (виртуальных) соединений, сколько вы хотите внутри своего приложения, не перегружая брокера TCP-соединениями.

  2. Вы можете использовать один Channelдля всего. Однако, если у вас несколько потоков, рекомендуется использовать разные потоки Channelдля каждого потока.

    Безопасность потока канала в Руководстве по API Клиента Java :

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

    Там нет прямой связи между Channelи Queue. A Channelиспользуется для отправки команд AMQP посреднику. Это может быть создание очереди или подобное, но эти понятия не связаны друг с другом.

  3. Каждый Consumerработает в своем собственном потоке, выделенном из пула потребительских потоков. Если несколько потребителей подписаны на одну и ту же очередь, брокер использует циклический перебор для равномерного распределения сообщений между ними. См. Учебное пособие два: «Очереди работы» .

    Также возможно прикрепить одно и то же Consumerк нескольким очередям. Вы можете понимать Потребителей как обратные вызовы. Они вызываются каждый раз, когда сообщение поступает в очередь, к которой привязан потребитель. Для случая Клиента Java у каждого Потребителя есть метод handleDelivery(...), который представляет метод обратного вызова. Что вы обычно делаете, это подкласс DefaultConsumerи переопределение handleDelivery(...). Примечание. Если вы подключите один и тот же экземпляр Consumer к нескольким очередям, этот метод будет вызываться разными потоками. Поэтому позаботьтесь о синхронизации при необходимости.

Бенгт
источник
4
Просто добавьте из документации: обратные вызовы для потребителей отправляются в потоке, отдельном от потока, управляемого соединением. Это означает, что потребители могут безопасно вызывать методы блокировки в соединении или канале, такие как queueDeclare, txCommit, basicCancel или basicPublish. Каждый канал имеет свой собственный поток рассылки. Для наиболее распространенного варианта использования одного Потребителя на канал это означает, что Потребители не задерживают других Потребителей. Если у вас есть несколько Потребителей на Канал, имейте в виду, что долго работающий Потребитель может задержать отправку обратных вызовов другим Потребителям на этом Канале.
Филипп
1
Если вы подключите один и тот же экземпляр Consumer к нескольким очередям из одного и того же канала, это будет означать, что обратные вызовы отправляются в один и тот же поток. В этом случае вам не нужна синхронизация, не так ли?
Филипп
Могу ли я использовать только одно соединение и использовать пул каналов вместо пула соединений? Повлияет ли это на пропускную способность публикации сообщений?
Qeek
4
Я думаю, что эта ссылка на Java Client API устарела, и фактически сегодняшняя ссылка прямо противоречит цитате в этом ответе. Сегодняшняя ссылка гласит: «Экземпляры канала не должны совместно использоваться потоками».
Эдвин Далорсо
1
@ EdwinDalorzo - похоже, тот, кто изначально написал документацию, не полностью понимал дихотомию соединения канала. Фундаментальная архитектура AMQP 0.9.1 действительно обрабатывает канал как сеанс, поэтому разные потоки, совместно использующие сеанс, на самом деле не имеют смысла. Я думаю, что это причина изменений.
Май
54

Здесь полезно хорошее концептуальное понимание того, что делает протокол AMQP «под капотом». Я хотел бы предложить, что документация и API, которые AMQP 0.9.1 выбрал для развертывания, делают это особенно запутанным, поэтому сам вопрос - это вопрос, с которым приходится сталкиваться многим.

TL; DR

Соединение является физическим переговорами TCP сокета с сервером AMQP. Правильно реализованные клиенты будут иметь один из них для каждого приложения, потокобезопасный, разделяемый между потоками.

Канал представляет собой один сеанс приложения на связи. Поток будет иметь один или несколько из этих сеансов. Архитектура AMQP 0.9.1 заключается в том, что они не предназначены для совместного использования между потоками и должны быть закрыты / уничтожены, когда созданный им поток завершит работу с ним. Они также закрываются сервером при различных нарушениях протокола.

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

Факты подключения

Во-первых, как правильно отметили другие, соединение - это объект, представляющий фактическое TCP-соединение с сервером. Соединения указываются на уровне протокола в AMQP, и вся связь с брокером происходит через одно или несколько соединений.

  • Поскольку это фактическое TCP-соединение, у него есть IP-адрес и номер порта.
  • Параметры протокола согласовываются для каждого клиента как часть настройки соединения (процесс, известный как квитирование .
  • Это разработано, чтобы быть долговечным ; Есть несколько случаев, когда закрытие соединения является частью дизайна протокола.
  • С точки зрения OSI, он, вероятно, находится где-то около уровня 6
  • Пульс может быть настроен для мониторинга состояния соединения, так как TCP не содержит ничего для этого сам по себе.
  • Лучше всего, чтобы выделенный поток управлял чтением и записью в базовый сокет TCP. Большинство, если не все, клиенты RabbitMQ делают это. В связи с этим они, как правило, потокобезопасны.
  • Условно говоря, соединения «дороги» в создании (из-за рукопожатия), но практически это не имеет значения. Большинству процессов действительно нужен только один объект подключения. Но вы можете поддерживать соединения в пуле, если обнаружите, что вам нужна более высокая пропускная способность, чем может обеспечить один поток / сокет (маловероятно для современных вычислительных технологий).

Факты о канале

Канал является приложением сеанса , который открыт для каждой части вашего приложения , чтобы общаться с RabbitMQ брокером. Он работает через одно соединение и представляет сеанс с брокером.

  • Поскольку он представляет логическую часть логики приложения, каждый канал обычно существует в своем собственном потоке.
  • Как правило, все каналы, открытые вашим приложением, будут использовать одно соединение (это облегченные сеансы, которые работают поверх соединения). Соединения потокобезопасны, так что все в порядке.
  • Большинство операций AMQP происходит по каналам.
  • С точки зрения уровня OSI, каналы, вероятно, находятся вокруг уровня 7 .
  • Каналы предназначены для переходных процессов ; Часть дизайна AMQP заключается в том, что канал обычно закрывается в ответ на ошибку (например, повторное объявление очереди с другими параметрами перед удалением существующей очереди).
  • Поскольку они временные, каналы не должны объединяться вашим приложением.
  • Сервер использует целое число для идентификации канала. Когда поток, управляющий соединением, получает пакет для определенного канала, он использует этот номер, чтобы сообщить посреднику, к какому каналу / сеансу принадлежит пакет.
  • Каналы, как правило, не являются потокобезопасными, поскольку не имеет смысла делить их между потоками. Если у вас есть другой поток, который должен использовать брокера, необходим новый канал.

Потребительские факты

Потребитель - это объект, определенный протоколом AMQP. Это не канал и не соединение, а то, что ваше конкретное приложение использует в качестве своего рода «почтового ящика» для отбрасывания сообщений.

  • «Создание потребителя» означает, что вы сообщаете брокеру (используя канал через соединение ), что хотите, чтобы сообщения передавались вам по этому каналу. В ответ брокер зарегистрирует, что у вас есть потребитель на канале, и начнет рассылать вам сообщения.
  • Каждое сообщение, передаваемое через соединение, будет ссылаться как на номер канала, так и на номер потребителя . Таким образом, поток управления соединениями (в данном случае в Java API) знает, что делать с сообщением; затем поток обработки канала также знает, что делать с сообщением.
  • Потребительская реализация имеет самые широкие вариации, потому что она буквально зависит от приложения. В моей реализации я выбрал выделение задачи каждый раз, когда сообщение поступало от потребителя; таким образом, у меня был поток, управляющий соединением, поток, управляющий каналом (и, соответственно, потребителем), и один или несколько потоков задач для каждого сообщения, доставляемого через потребителя.
  • Закрытие соединения закрывает все каналы соединения. Закрытие канала закрывает всех потребителей на канале. Также можно отменить потребителя (без закрытия канала). Существуют различные случаи, когда имеет смысл сделать любую из трех вещей.
  • Как правило, реализация потребителя в клиенте AMQP выделяет потребителю один выделенный канал, чтобы избежать конфликтов с действиями других потоков или кода (включая публикацию).

С точки зрения того, что вы подразумеваете под пулом потребительских потоков, я подозреваю, что Java-клиент делает нечто похожее на то, что я запрограммировал для моего клиента (мой был основан на .Net-клиенте, но сильно изменен).

theMayer
источник
1
«каналы не должны объединяться», вот что я ищу
ospider
«Поскольку они временные, каналы не должны объединяться вашим приложением». - Не могли бы вы уточнить, как вы пришли к такому выводу, пожалуйста. Документы рекомендуют объединение каналов, если реализация «один канал на поток» использует слишком много ресурсов, см. Здесь: rabbitmq.com/channels.html#resource-usage
ymas
@ymas - документация, на которую вы ссылаетесь, носит умозрительный характер и, на мой взгляд, плохое руководство. Я читаю исходный код и спецификации протокола. Каналы не должны быть объединены, точка. Кроме того, один канал на поток является руководством, основанным на этом же принципе. Если вы обнаружите, что у вас так много открытых каналов, что сервер ограничен в ресурсах, вам необходимо пересмотреть свою архитектуру (т. Е. Перейти на схему высокой доступности и / или уменьшить параллелизм).
The Mayer
21

Я нашел эту статью, которая объясняет все аспекты модели AMQP, одним из которых является канал. Я нашел это очень полезным в завершении моего понимания

https://www.rabbitmq.com/tutorials/amqp-concepts.html

Некоторым приложениям требуется несколько подключений к брокеру AMQP. Однако нежелательно держать открытыми многие TCP-соединения одновременно, поскольку это потребляет системные ресурсы и усложняет настройку брандмауэров. Соединения AMQP 0-9-1 мультиплексируются с каналами, которые можно рассматривать как «облегченные соединения, которые совместно используют одно TCP-соединение».

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

Связь по определенному каналу полностью отделена от связи по другому каналу, поэтому каждый метод AMQP также несет номер канала, который клиенты используют, чтобы выяснить, для какого канала предназначен метод (и, таким образом, например, какой обработчик события должен быть вызван) ,

CamW
источник
4

Существует связь между аналогами. Соединение TCP может иметь несколько каналов .

Канал : это виртуальное соединение внутри соединения. При публикации или использовании сообщений из очереди - все это делается по каналу, тогда как Connection : это TCP-соединение между вашим приложением и брокером RabbitMQ.

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

Атул Джайн
источник