ActiveMQ:如何在使用临时队列时处理经纪人故障转移

55

在我的JMS应用程序中,我们使用生产者上的临时队列来接收来自消费者应用程序的回复。

我遇到了与此线程中提到的完全相同的问题:http://activemq.2283324.n4.nabble.com/jira-Created-AMQ-3336-Temporary-Destination-errors-on-H-A-failover-in-broker-network-with-Failover-tt-td3551034.html#a3612738

每当我在网络中重新启动任意代理时,我的消费者应用程序日志中就会出现许多类似于以下内容的错误,而尝试发送回复到临时队列时会出现这些错误:

javax.jms.InvalidDestinationException:
  Cannot publish to a deleted Destination: temp-queue://ID:...

然后我看到Gary在那里建议使用

jms.watchTopicAdvisories=false

作为客户端brokerURL的url参数。我立即使用这个额外的参数更改了我的客户端经纪人URL。但是,现在当我重新启动用于此故障转移测试的代理时,我会看到像这样的错误:

javax.jms.JMSException: 
  The destination temp-queue:
    //ID:client.host-65070-1308610734958-2:1:1 does not exist.

我正在使用ActiveMQ 5.5版本。我的客户端代理URL看起来像这样:

failover:(tcp://amq-host1:61616,tcp://amq-host2.tred.aol.com:61616,tcp://amq-host3:61616,tcp://amq-host4:61616)?jms.useAsyncSend=true&timeout=5000&jms.watchTopicAdvisories=false
 

此外,这是我其中一个4个代理的activemq配置XML:

amq1.xml

请有经验的人查看这个问题,并建议我在此设置中犯了什么错误。

更新:

为了更进一步说明我在代码中如何进行请求-响应:

  1. 我已经使用每个生产者目的地(即临时队列),并将其设置在每条消息的回复头中。
  2. 我已经在JMSCorrelationID头中发送每个消息的唯一关联标识符。
  3. 据我所知,即使是Camel和Spring也在使用临时队列进行请求-响应机制。唯一的区别是,Spring JMS实现会为每个消息创建和销毁临时队列,而我为生产者的生命周期创建临时队列。该临时队列在客户端(生产者)应用程序关闭或AMQ代理发现没有连接到该临时队列的活动生产者时将被销毁。
  4. 我已经在生产者端的每个消息上设置了消息过期时间,以便消息不会在队列中被保留太长时间(60秒)。

1
新的 JMSException 只是被记录在日志中还是会抛出到客户端代码中?此外,异常是否会在客户端发送到代理的每个消息上抛出,或者当故障转移完成时异常是否停止?(即,异常只在客户端未连接时抛出吗?) - user545680
2
除了 jms.watchTopicAdvisories=false 之外,似乎还需要做一些其他事情,例如在 XML 配置中添加 <broker advisorySupport="false">,以及静态配置您的网络。(您的 amq1.xml 文件给我返回了 404 Not Found) - opyate
1
@Bringer128:感谢您的评论。该JMS异常是在生产者重新连接后连接到的另一个AMQ代理服务器上抛出的。一旦发生这种情况,JMS生产者就会停止接收来自消费者的任何响应,因为AMQ代理服务器无法通过上述JMS异常将回复发送回生产者。 - anubhava
2
@opyate:感谢您的建议。 但是,仅告知您,即使使用 staticallyIncludedDestinations,在当前的AMQ5.5版本中,带有advisorySupport="false"的临时目标也不起作用。 但是,根据我的要求,此功能已添加到即将发布的5.6版本中。 请参见我与Gary Tully的对话,链接在此处:http://activemq.2283324.n4.nabble.com/network-of-broker-stop-forwarding-messages-without-advisorySupport-enabled-td3386261.html,以获取更多详细信息。 - anubhava
2个回答

27

有一个代理属性,org.apache.activemq.broker.BrokerService#cacheTempDestinations,可以帮助处理故障转移的情况。 在xml配置中将其设置为true,当客户端断开连接时,临时队列不会立即被删除。 快速的故障恢复重新连接后将能够从临时队列生产和/或消费。

基于timeBeforePurgeTempDestinations(默认为5秒)的计时器任务用于处理缓存清除。

然而需要注意的是,我没有看到activemq-core中有任何使用该属性的测试,因此无法对其作出保证。


1
如果你注意到我的问题中写道:“每当我重新启动网络中的任意代理”,那么我想知道,如果代理本身被重新启动,这个代理属性cacheTempDestinations会有什么影响? - anubhava
4
当您重新启动代理时,任何临时目标以及其中的任何未决消息都将丢失。对于临时目标,代理没有维护持久状态。 - gtully
我们能做的最好的事情是:1)支持故障转移:重新连接到现有代理。2)在代理之间存在网络分区或在发送临时目标的回复之前代理失败的情况下,允许自动创建临时目标。 - gtully
我已经在我的JMS客户端URL中使用了failover:来连接AMQ集群。当您编写“允许自动创建临时目标”时,您是指允许在某个活动代理中自动创建临时目标以应对某个随机代理死亡的情况吗?我的问题是如何获得此临时目标的自动创建? - anubhava
在支持AMQ-3253的情况下,添加了代理属性allowTempAutoCreationOnSend。 - gtully
看了一下这个JIRA,似乎AMQ 5.6.0中添加了allowTempAutoCreationOnSend属性,而不是当前的5.5.0版本?如果是这样的话,我将不得不等待5.6.0版本最终发布,因为我们的运营政策不允许使用beta、RC或快照版本。 - anubhava

10
Temporary queues是在代理服务器上创建的,请求-响应方案中的请求者(生产者)连接到它们。它们是从javax.jms.Session创建的,因此当该会话断开连接时,无论是由于客户端断开还是代理服务器故障/故障转移,这些队列都将永久消失。当您的某个消费者尝试回复这些队列时,其他任何代理服务器都不会理解其含义,因此会出现异常。
这需要一种架构思维上的转变,假设您想处理故障转移并持久化所有消息。以下是解决问题的一般方式:
  1. 您的回复标头应该引用特定于请求进程的队列:例如,queue:response.<client id>。如果您只有有限数量的客户端,则客户端ID可能是标准名称,否则可能是UUID。
  2. 出站消息应设置相关标识符(仅是一个字符串,可让您将请求与响应关联起来 - 毕竟,请求者可能同时发出多个请求)。这在JMSCorrelationID标头中设置,并且应从请求复制到响应消息。
  3. 请求者需要在该队列上设置侦听器,该侦听器将根据该相关性ID将消息正文返回给请求线程。需要编写一些多线程代码,因为您需要手动管理类似于相关性ID到原始线程的映射(可能通过Futures)的内容。

这是Apache Camel用于通过消息进行请求-响应的类似方法。

需要注意的一件事是,当客户端结束时,队列不会消失,因此您应该设置响应消息的生存时间,以便如果它未被消费,则从代理中删除,否则您将获得未消费消息的积压。您还需要设置死信队列策略以自动丢弃已过期的消息


感谢您详细的回答。我已经在我的问题中添加了一个更新部分,以回应您所有的观点。您是否偶然建议我不要每个生产者使用临时队列? - anubhava
没错,临时队列并不是为故障转移而设计的 - 它们是客户端和代理之间通过会话达成的协议;会话位于单个连接上。Camel默认使用临时队列进行请求-响应,但由于上述原因通常不切实际,因此支持静态队列作为回退以满足该服务质量(尽管它使用JMS选择器在队列上进行相关性,出于性能原因应避免这样做)。 - Jakub Korab
如果您选择这条路,请求者应该以一种不会冲突的方式命名他们所监听的队列。如果您的请求者与GUI实例或主机名相关联,您可以使用uuid和实际用户ID的组合,或者使用主机名(我见过这两种方法的使用)- 关键是确保队列名称是唯一的。 - Jakub Korab
如果您注意到这些都是临时队列的特征。而且,如果每个生产者开始创建唯一命名的队列,那么如果生产者突然死亡,它们将如何清理? - anubhava
我实际上已经尝试过destinationPolicy中这两个gc选项,并发现在broker网络中它并不能像应该的那样工作(可能是因为有advisory subscriptions)。一旦我在没有broker网络的情况下运行这些选项,那么gc就会顺利进行。然而,当AMQ 5.6.0发布时,我愿意再次测试它。 - anubhava
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接