RabbitMQ和通道与连接之间的关系

158 java messaging channel amqp rabbitmq

RabbitMQ的Java客户端具有以下概念:

  • Connection - 与RabbitMQ服务器实例的连接
  • Channel - ???
  • 使用者线程池 - 使用RabbitMQ服务器队列消息的线程池
  • 队列 - 以FIFO顺序保存消息的结构

我想了解的关系,更重要的是,该协会之间.

  1. 我还不太确定它Channel是什么,除了这是你发布和使用的结构,以及它是从一个开放的连接创建的.如果有人可以向我解释"频道"代表什么,那么可能有助于澄清一些事情.
  2. 频道和队列之间有什么关系?可以使用相同的通道与多个队列进行通信,还是必须为1:1?
  3. Queue和Consumer Pool之间有什么关系?多个消费者可以订阅同一个队列吗?同一个消费者可以使用多个队列吗?或者是1:1的关系?

在此先感谢您的帮助!

Ben*_*ngt 178

  1. A Connection表示与消息代理的真实TCP连接,而a Channel是其中的虚拟连接(AMPQ连接).这样,您可以在应用程序中使用任意数量的(虚拟)连接,而无需使用TCP连接重载代理.

  2. 您可以使用一个Channel.但是,如果您有多个线程,则建议Channel对每个线程使用不同的线程.

    Java客户端API指南中的通道线程安全性:

    通道实例可安全地供多个线程使用.对通道的请求是序列化的,只有一个线程能够一次在通道上运行命令.即便如此,应用程序应该更喜欢每个线程使用一个Channel而不是跨多个线程共享相同的Channel.

    Channel和之间没有直接关系Queue.A Channel用于将AMQP命令发送到代理.这可以是队列或类似的创建,但这些概念并没有捆绑在一起.

  3. 每个都Consumer在从消费者线程池分配的自己的线程中运行.如果多个使用者订阅了同一个队列,则代理使用循环法在它们之间平均分配消息.请参阅教程二:"工作队列".

    也可以将它附加Consumer到多个队列.您可以将消费者理解为回调.每当消息到达Consumer绑定的Queue时,就会调用它们.对于Java客户端的情况,每个消费者都有一个方法handleDelivery(...),它表示回调方法.你通常做的是,子类DefaultConsumer和覆盖handleDelivery(...).注意:如果将同一个Consumer实例附加到多个队列,则此方法将由不同的线程调用.因此,如有必要,请注意同步.

  • 只是从文档中添加:消费者的回调是在与Connection管理的线程分开的线程上调度的.这意味着消费者可以安全地在Connection或Channel上调用阻塞方法,例如queueDeclare,txCommit,basicCancel或basicPublish.每个Channel都有自己的调度线程.对于每个渠道一个消费者的最常见用例,这意味着消费者不会阻止其他消费者.如果每个频道有多个消费者,请注意长时间运行的消费者可能会阻止向该频道上的其他消费者发送回调. (4认同)
  • 我认为这个对Java Client API的引用现在已经过时了,事实上今天的引用直接与本答案中的引用相矛盾.今天的参考文献说"不能在线程之间共享通道实例". (4认同)
  • 如果您将同一个 Consumer 实例附加到同一 Channel 的多个队列,则意味着回调将在同一个线程上分派。在这种情况下,您不需要同步,对吗? (2认同)

the*_*yer 44

对于AMQP协议在"引擎盖下"做什么的一个很好的概念性理解在这里是有用的.我建议AMQP 0.9.1选择部署的文档和API使这一点特别混乱,因此问题本身就是许多人不得不努力解决的问题.

TL; DR

一个连接与AMQP服务器的物理协商TCP套接字.正确实现的客户端将具有每个应用程序中的一个,线程安全,可在线程之间共享.

信道是连接上的单个应用会话.线程将具有一个或多个这些会话.AMQP体系结构0.9.1是这些不在线程之间共享,并且应该在创建它的线程完成时关闭/销毁它们.当发生各种协议违规时,服务器也会关闭它们.

消费者是表示一个"信箱"的特定频道上的存在的虚拟构建体.使用者告诉代理将消息从特定队列推送到该通道端点.

连接事实

首先,正如其他人正确指出的那样,连接是表示与服务器的实际TCP连接的对象.连接在AMQP中的协议级别指定,并且与代理的所有通信都通过一个或多个连接进行.

  • 由于它是一个实际的TCP连接,它有一个IP地址和端口#.
  • 协议参数是基于每个客户端协商的,作为建立连接的一部分(称为握手的过程).
  • 它的设计是长寿的 ; 连接闭包是协议设计的一部分的情况很少.
  • 从OSI的角度来看,它可能位于第6层的某个地方
  • 可以设置心跳来监视连接状态,因为TCP本身不包含任何内容来执行此操作.
  • 最好有一个专用线程管理对底层TCP套接字的读写操作.大多数(如果不是全部)RabbitMQ客户端都这样做.在这方面,它们通常是线程安全的.
  • 相对来说,连接"创建起来很昂贵"(由于握手),但实际上,这并不重要.大多数进程实际上只需要一个连接对象.但是,如果您发现需要比单个线程/套接字所能提供的更多吞吐量(不太可能使用当前的计算技术),则可以在池中维护连接.

渠道事实

一个通道是打开的,每件您的应用程序与RabbitMQ的代理进行通信的应用程序会话.它通过单个连接运行,并代表与代理的会话.

  • 由于它代表了应用程序逻辑的逻辑部分,因此每个通道通常都存在于自己的线程中.
  • 通常,您的应用程序打开的所有频道都将共享一个连接(它们是在连接之上运行的轻量级会话).连接是线程安全的,所以这没关系.
  • 大多数AMQP操作都是通过渠道进行的.
  • 从OSI Layer的角度来看,渠道可能在第7层.
  • 通道设计为瞬态 ; AMQP的部分设计是通道通常在响应错误时关闭(例如,在删除现有队列之前重新声明具有不同参数的队列).
  • 由于它们是短暂的,因此您的应用不应将频道合并.
  • 服务器使用整数来标识通道.当管理连接的线程接收到特定信道的分组时,它使用该号码告诉代理该分组属于哪个信道/会话.
  • 通道通常不是线程安全的,因为在线程之间共享它们是没有意义的.如果您有另一个需要使用代理的线程,则需要新的通道.

消费者事实

使用者是由AMQP协议定义的对象.它既不是通道也不是连接,而是您的特定应用程序用作丢弃消息的"邮箱"的东西.

  • "创建消费者"意味着您告诉代理(通过连接使用频道)您希望通过该频道向您推送消息.作为回应,经纪人将注册您在频道上有消费者并开始向您推送消息.
  • 通过连接推送的每条消息都将引用频道号消费者号码.通过这种方式,连接管理线程(在这种情况下,在Java API中)知道如何处理消息; 然后,通道处理线程也知道如何处理该消息.
  • 消费者实施具有最广泛的变化,因为它实际上是应用程序特定的.在我的实现中,我选择在每次通过消费者到达消息时分离任务; 因此,我有一个管理连接的线程,一个管理通道(和扩展,消费者)的线程,以及通过消费者传递的每个消息的一个或多个任务线程.
  • 关闭连接会关闭连接上的所有通道.关闭频道会关闭频道上的所有消费者.也可以取消消费者(不关闭频道).在有三种情况的任何一种情况下,有各种各样的情况.
  • 通常,AMQP客户端中的消费者的实现将向消费者分配一个专用信道,以避免与其他线程或代码(包括发布)的活动冲突.

就消费者线程池的含义而言,我怀疑Java客户端正在做类似于我编写客户端的事情(我的基于.Net客户端,但经过大量修改).

  • “频道不应合并”,这就是我正在寻找的 (3认同)

Cam*_*amW 20

我发现这篇文章解释了AMQP模型的所有方面,其中,渠道就是其中之一.我觉得这对我的理解非常有帮助

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

某些应用程序需要与AMQP代理程序建立多个连接.但是,不希望同时打开许多TCP连接,因为这样做会消耗系统资源并使配置防火墙变得更加困难.AMQP 0-9-1连接与可被视为"共享单个TCP连接的轻量级连接"的通道复用.

对于使用多个线程/进程进行处理的应用程序,每个线程/进程打开一个新通道并且不在它们之间共享通道是很常见的.

特定通道上的通信与另一个通道上的通信完全分开,因此每个AMQP方法还带有一个通道号,客户端使用该通道号来确定该方法所针对的通道(例如,需要调用哪个事件处理程序) .


Atu*_*ain 5

就像一个 TCP 连接可以有多个 Channels之间有一个关系。

通道:它是一个连接内的虚拟连接。从队列发布或使用消息时 - 全部通过通道完成 而Connection:它是您的应用程序和 RabbitMQ 代理之间的 TCP 连接。

在多线程架构中,每个线程可能需要一个单独的连接。这可能会导致 TCP 连接未得到充分利用,还会增加操作系统的开销,以便在网络高峰时间建立所需的 TCP 连接。系统的性能可能会大大降低。这是通道派上用场的地方,它在 TCP 连接内创建虚拟连接。它直接减少了操作系统的开销,还允许我们以更快、更可靠和同步的方式执行异步操作。 在此处输入图片说明