2012-05-10 190 views
2

我继承了一些传统的RabbitMQ代码,这给我带来了一些严重的麻烦。任何人都可以帮助,理想情况下指向一些“官方”文档在哪里我可以浏览类似的问题?RabbitMQ多线程通道和队列绑定

我们创造一些渠道获得来自工人,其执行使用渠道,像这样一个搜索响应:

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

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

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

这是真的吗?

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

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

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

回答

0

我不能确定这将在多线程环境中工作。很高的比例可能会很好,但有可能你会得到错误的队列。为什么要冒这个险? 这不会更好更安全吗?

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

不完全笨重。

+0

你是对的。这并不糟糕。以为我不得不用返回对象做一些查找。很高兴知道预期的行为,因为我的代码库中还有其他类似的模糊行。 – milletron

+0

如果有类似的模糊线条,我会优先考虑寻找方法,像这样去除模糊性。也许最初的代码是为早期版本的API编写的,现在有更好的方法来处理这种情况。总的来说,如果使用正确,rabbitMQ客户端应该是线程安全的。 – robthewolf

+0

真的希望找到一个指向一些文档的指针(即不仅仅是StackOverflow文章和RabbitMQ列表)关于如何处理错误,连接关闭时会发生什么,如果尝试打开两个通道会发生什么......这种排序的东西。我想我会继续通过试验和错误一件一件地移植东西。 – milletron

0

问:当队列没有名称申报,会发生什么?

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

问:队列名称必须是全球唯一的? A:不,但他们可能需要在您的使用案例中。任何数量的发布者和订阅者都可以共享一个队列。队列声明是幂等的,所以如果2个客户端同时声明一个具有相同名称和设置的队列,或者在不同的时间,那么服务器状态将与只有一个声明它的队列相同。然而,空白名称的队列永远不会发生冲突。考虑用一个空白名称来声明一个队列,就好像它是两个操作一样:一个RPC询问RabbitMQ“给我一个全局唯一的名称,你将保留这个名字给我使用”,然后用这个名字声明一个队列。

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

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

相反,使用的queueDeclare的返回值;该返回值将包含已声明队列的名称。 如果您声明了一个没有名字的队列,则返回值queueDeclare将包含由RabbitMQ提供的新的全局唯一名称。你可以明确地提供与该队列一起工作的后续调用(如绑定它)。

支付额外的理由不这样做,对于空队列名称的行为documentation是非常暧昧:

客户端必须指定一个队列名称,或者以前 宣布对同一个队列通道

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

问:队列被删除连接到他们“下”的渠道?

答:是的,在特定的情况。对你的问题的术语作了小的澄清:通道不会将自己“绑定”到队列中:尽管如此,通道可以占用一个队列。想象一个像网络端口和远程对等体这样的通道:您不会将端口绑定到远程对等端,但您可以通过同一个端口与多个对等端通信。消费者相当于连接的套接字;不是渠道。总之:

通道不事在这里,但消费者和连接都(可以有不止一个消费者,甚至同一个队列,每个信道,可以有每个连接多个信道)。下面是一个队列可以被删除的情况,“在”频道订阅它的地方(我可能错过了一些,但这些都是非灾难性的 - 例如我知道的“服务器爆炸”条件):

  1. 队列被声明为exclusive设置为true,并且声明队列的连接关闭。用于声明队列的通道可以关闭,但只要连接保持打开状态,队列就会保持存在。连接到专用队列的客户端将看到它消失。但是,如果客户“锁定”到其声明者,则客户可能无法首先访问专用队列以供消费。the documentation不清楚“使用”关于排他锁定的含义。
  2. 通过queue.delete调用手动删除的队列。在这种情况下,连接到队列的所有用户在下次尝试使用它时可能会遇到错误。

注意,在很多情况下,客户端,消费者往往是“被动” 不够,他们不会意识到队列消失了;他们只会 永远听取什么是有效的封闭套接字。发布到 的队列,或试图用passive(存在 轮询)重新声明它可以保证不存在;消费单独 不是:有时你会看到一个“这个队列被删除了!”错误, 有时需要几分钟或几小时才能到达,有时候如果您所做的所有事情都在消耗,那么您将不会看到这样的错误。

问:当另一个消费者退出时,auto_delete队列会被“删除”下面的一个消费者删除吗?

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

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