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

时间:2013-08-24 13:08:11

标签: java rabbitmq messaging amqp channel

RabbitMQ Java client具有以下概念:

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

我正在尝试理解它们之间的关系,,更重要的是关联

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

3 个答案:

答案 0 :(得分:166)

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

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

    Channel thread-safety in Java Client API Guide

      

    多个线程可以安全地使用通道实例。请求进入   频道被序列化,只有一个线程能够运行a   一次命令在频道上。即便如此,应用程序应该更喜欢   每个线程使用一个Channel而不是共享同一个Channel   多线程。

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

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

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

答案 1 :(得分:36)

一个很好的概念性理解AMQP协议的作用"引擎盖下#34;在这里很有用。我建议AMQP 0.9.1选择部署的文档和API使这一点特别混乱,因此问题本身就是许多人不得不与之搏斗的问题。

<强> TL; DR

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

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

使用者是一个虚拟结构,表示存在&#34;邮箱&#34;在特定的频道上。消费者的使用告诉代理将消息从特定队列推送到该通道端点。

关联事实

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

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

频道事实

频道是为每个应用程序打开的应用程序会话,以便与RabbitMQ代理进行通信。它通过单个连接运行,并代表与代理的会话

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

消费者事实

使用者是AMQP协议定义的对象。它既不是一个频道也不是一个连接,而是你的特定应用程序用作&#34;邮箱&#34;删除邮件的种类。

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

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

答案 2 :(得分:19)

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

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

  

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

     

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

     

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