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

anu*_*ava 52 java activemq-classic jms failovercluster

在我的JMS应用程序上,我们在Producers上使用临时队列,以便能够从Consumer应用程序接收回复.

我在这个主题中提到的完全相同的问题:http://activemq.2283324.n4.nabble.com/jira-Created-AMQ-3336-Temporary-Destination-errors-on-HA-failover-in -broker-网络与故障转移-TT-td3551034.html#a3612738

每当我在网络中重新启动一个任意代理时,在尝试将回复发送到临时队列时,我在使用者应用程序日志中收到了许多这样的错误:

javax.jms.InvalidDestinationException:
  Cannot publish to a deleted Destination: temp-queue://ID:...
Run Code Online (Sandbox Code Playgroud)

然后我看到加里在那里建议使用的回应

jms.watchTopicAdvisories=false
Run Code Online (Sandbox Code Playgroud)

作为客户端的URL参数brokerURL.我使用此附加参数立即更改了客户端代理URL.但是现在,当我在网络中重新启动我的代理进行此故障转移测试时,我发现这样的错误:

javax.jms.JMSException: 
  The destination temp-queue:
    //ID:client.host-65070-1308610734958-2:1:1 does not exist.
Run Code Online (Sandbox Code Playgroud)

我使用的是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
Run Code Online (Sandbox Code Playgroud)

另外,这是我的4个代理之一的activemq配置XML: amq1.xml

有人可以在这里查看这个问题并建议我在这个设置中犯了什么错误.

更新:

为了进一步澄清我在代码中如何进行请求 - 响应:

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

gtu*_*lly 25

有一个代理属性org.apache.activemq.broker.BrokerService #cacheTempDestinations应该有助于故障转移:case.在xml配置中将其设置为true,并且在客户端断开连接时不会立即删除临时目标.快速故障转移:重新连接将能够再次从临时队列生成和/或使用.

有一个基于timeBeforePurgeTempDestinations(默认为5秒)的计时器任务,用于处理缓存删除.

但有一点需要注意,我没有在activemq-core中看到任何使用该属性的测试,因此我无法对此给出任何保证.

  • 重新启动代理时,任何临时目标将与任何挂起的消息一起丢失.经纪人没有为临时目的地维护持久状态. (4认同)

Jak*_*rab 9

在请求 - 应答方案中请求者(生产者)连接的代理上创建临时队列.它们是从a创建的javax.jms.Session,因此在该会话断开连接时,由于客户端断开连接或代理失败/故障转移,这些队列永久消失.当你的一个消费者试图回复这些队列时,其他经纪人都不会理解其含义; 因此你的例外.

这需要在思维模式上进行架构转换,假设您要处理故障转移并保留所有消息.以下是您可以解决问题的一般方法:

  1. 您的回复标题应该引用特定于请求者进程的队列:例如queue:response.<client id>.如果您的客户端数量有限,则客户端ID可能是标准名称;如果您拥有大量客户端,则客户端ID可能是UUID.
  2. 出站消息应该设置一个相关标识符(只是一个sting,它允许您将请求与响应相关联 - 请求者可能同时发出多个请求).这是在JMSCorrelationID标题中设置的,应该从请求复制到响应消息.
  3. 请求者需要在该队列上设置一个侦听器,该侦听器将根据该相关ID将消息体返回给请求线程.有一些需要为此编写的多线程代码,因为您需要手动管理诸如相关ID的映射到原始线程(可能通过Futures).

这与Apache Camel针对消息传递的请求 - 响应采用的方法类似.

需要注意的一点是,当客户端执行时,队列不会消失,所以你应该设置一个时间来生成响应消息,这样如果没有消耗它就会从代理中删除,否则你会得到积压的未消耗的消息.您还需要设置死信队列策略以自动丢弃过期的消息.