RabbitMQ多线程通道和队列绑定

时间:2012-05-10 18:24:05

标签: java multithreading rabbitmq amqp

我继承了一些传统的RabbitMQ代码,这给我带来了一些严重的麻烦。任何人都可以帮忙,理想情况下指向一些“官方”文档,我可以浏览类似的问题吗?

我们创建一些渠道接收来自工作人员的回复,这些回复使用如下渠道执行搜索:

channelIn.queueDeclare("", false, false, true, null);
channelIn.queueBind("", AmqpClient.NAME_EXCHANGE,
     AmqpClient.ROUTING_KEY_ROOT_INCOMING + uniqueId);

我对浏览邮件列表和论坛的理解是

  • 声明具有空名称的队列允许服务器自动生成唯一名称,并且
  • 队列必须具有全局唯一名称。

这是真的吗?

此外,在上面的第二行中,我基于对博客和邮件列表的一些自由解释的理解是具有空队列名称的queuebind自动绑定到最后创建的队列。这看起来不错,因为那时你不必从笨重的DeclareOK对象中拉出自动生成的名称。

这是真的吗?如果是这样,这将在多线程环境中工作吗?

即。是否有可能某个通道将自己绑定到另一个通道的队列,如果其他通道关闭,错误绑定的通道会在尝试使用队列时出错? (请注意,队列是使用autodelete = true创建的。)我的测试让我想到了,但我不确定问题出在哪里。

2 个答案:

答案 0 :(得分:0)

我无法确定这是否适用于多线程环境。它可能在很高的时间内很好,但你可能会得到错误的队列。为什么要承担风险? 这不会更好更安全吗?

String queueName = channelIn.queueDeclare("", false, false, true, null).getQueue();
channelIn.queueBind(queueName, AmqpClient.NAME_EXCHANGE,
 AmqpClient.ROUTING_KEY_ROOT_INCOMING + uniqueId);

不完全笨重。

答案 1 :(得分:0)

问:声明没有名字的队列会发生什么?

答:服务器为队列选择一个唯一的名称。当没有提供名称时,RabbitMQ服务器将生成一个唯一的RabbitMQ集群名称,用它创建一个队列name,然后将名称传回给调用queue.declare的客户端。 RabbitMQ在内部以线程安全的方式执行此操作(例如,许多使用空白名称调用queue.declare的客户端永远不会获得相同的名称)。 Here是有关此行为的文档。

问:队列名称是否必须全局唯一?

答:不,但他们可能需要处于您的使用案例中。任意数量的发布者和订阅者都可以共享队列。队列声明是幂等的,因此如果2个客户端同时或在不同时间声明具有相同名称和设置的队列,则服务器状态将与仅声明它的一个相同。但是,具有空白名称的队列永远不会发生冲突。考虑声明一个空白名称的队列,好像它是两个操作:一个RPC询问RabbitMQ"给我一个全局唯一的名称,你将保留它仅供我使用",然后幂等地声明一个具有该名称的队列

问:具有空白名称的queue.bind是否会绑定到多线程环境中最后创建的队列?

答:是的,但你不应该这样做;它没有任何成果,令人困惑,并且具有未指定/指定不当的行为。这种技术在很大程度上毫无意义,并且容易在客户端代码中出现错误(如果在声明和添加之间添加了行怎么办?那么它会非常很难确定绑定的队列。

相反,使用queueDeclare的返回值;返回值将包含声明的队列的名称。 如果您声明了一个没有名称的队列,则queueDeclare的返回值将包含RabbitMQ提供的新的全局唯一名称。您可以将该语言显式提供给与该队列一起使用的后续调用(比如绑定它)。

由于不这样做的另一个原因,关于空白队列名称行为的documentation非常不明确:

  

客户端必须指定队列名称或先前具有   在同一个频道上宣布一个队列

这是什么意思?如果声明了多个队列,哪个队列将被绑定?如果之前声明的队列随后在同一频道上删除了怎么办?这似乎是一个非常好的理由,尽可能明确,而不是依赖于这种行为。

问:队列是否会被删除""与他们相关的渠道?

答:是的,在特定情况下。对您问题的术语进行轻微澄清:渠道不要"绑定"他们自己到队列:一个频道可以消耗队列。可以考虑像网络端口这样的通道和像远程对等端一样的队列:您不要将端口绑定到远程对等端,但是您可以通过同一端口与多个对等端通信。消费者相当于连接插座;不是渠道。无论如何:

频道在这里并不重要,但消费者和连接确实存在(每个频道可以有多个消费者,甚至同一个队列;每个连接可以有多个频道)。以下是可以删除队列的情况""订阅它的频道(我可能错过了一些,但这些都是非灾难性的 - 例如。"服务器爆炸了#34;条件我知道):

  1. 声明队列,exclusive设置为true,声明队列的连接关闭。用于声明队列的通道可以关闭,但只要连接保持打开,队列就会保持存在。连接到独占队列的客户端将看到它消失。但是,如果客户端被锁定,则可能无法首先访问专用队列以进行消费。对于它的声明者 - the documentation并不清楚"使用了什么"关于独家锁定的意思。
  2. 通过queue.delete电话手动删除的队列。在这种情况下,连接到队列的所有使用者在下次尝试使用它时都可能会遇到错误。
  3. 注意在许多客户端情况下,消费者往往是被动的"     足够他们不会意识到队列已经消失;他们只是     永远听取什么是有效的封闭套接字。发布到     一个队列,或试图用passive重新声明它(存在     民意调查)保证表明不存在;仅消费     不是:有时你会看到一个"这个队列被删除了!"错误,     有时需要几分钟或几小时到达,有时候你     如果您所做的一切都在消耗,我们将永远不会看到这样的错误。

    问:auto_delete队列会被删除"在"下面当另一个消费者退出时,一个消费者?

    答: auto_delete队列在 last 消费者离开队列后的某个时间被删除。因此,如果您在auto_delete队列上启动两个使用者,则可以退出一个而不会打扰另一个。 Here's有关该行为的文档。

    此外,过期的队列(通过per-queue TTL)遵循相同的行为:队列只会在最后一个消费者离开后的某个时间消失。