在我的JMS应用程序上,我们在Producers上使用临时队列,以便能够接收来自Consumer应用程序的回复。
我面临着与本帖子中提到的完全相同的问题: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
每当我在网络中重新启动任意代理时,在尝试向临时队列发送回复时,我的Consumer应用程序日志中都会出现许多类似这样的错误:
javax.jms.InvalidDestinationException:
Cannot publish to a deleted Destination: temp-queue://ID:...
然后我看到Gary在那里建议使用
jms.watchTopicAdvisories=false
作为客户端CCD_ 1上的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
这里有人能调查一下这个问题,并建议我在这个设置中犯了什么错误吗。
更新:
为了进一步澄清我是如何在我的代码中进行请求响应的:
- 我已经使用了每个生产者的目的地(即临时队列),并将其设置为每个消息的头的回复
- 我已经在JMSCorrelationID标头中发送了每条消息的唯一相关性标识符
- 据我所知,甚至Camel和Spring也在使用临时队列请求响应机制。唯一的区别是SpringJMS实现为每条消息创建和销毁临时队列,而我为生产者的生命周期创建临时队列。当客户端(生产者)应用程序关闭时,或者当AMQ代理意识到没有活动生产者连接到此临时队列时,此临时队列将被销毁
- 我已经在Producer端为每条消息设置了消息过期时间,这样消息就不会在队列中停留太长(60秒)
有一个broker属性org.apache.activemq.broker.BrokerService#cacheTempDestinations应该有助于故障转移:case。在xml配置中设置为true,当客户端断开连接时,临时目标不会立即删除。快速故障转移:重新连接将能够再次从临时队列中生成和/或消费。
有一个基于timeBeforePurgeTempDestinations(默认为5秒)的计时器任务,用于处理缓存删除。
不过,有一点需要注意,我在activemq核心中没有看到任何使用该属性的测试,所以我不能保证这一点。
在请求-应答场景中的请求者(生产者)连接到的代理上创建临时队列。它们是从javax.jms.Session
创建的,因此,由于客户端断开连接或代理故障/故障转移,会话断开连接后,这些队列将永久消失。当你的一个消费者试图回复这些队列时,其他经纪人都不会理解这意味着什么;因此你的例外。
这需要在思维方式上进行架构转换,假设您希望处理故障转移并持久化所有消息。这里有一个可以解决问题的通用方法:
- 您对标头的回复应指向特定于请求程序进程的队列:例如
queue:response.<client id>
。如果客户端数量有限,则客户端id可能是一个标准名称,如果客户端数量很大,则可能是UUID - 出站消息应该设置一个关联标识符(简单地说,就是一个让您将请求与响应相关联的字符串——毕竟,请求者可能会同时发出多个请求)。这是在
JMSCorrelationID
标头中设置的,应该从请求复制到响应消息 - 请求者需要在该队列上设置一个侦听器,该侦听器将根据相关id向请求线程返回消息正文。需要为此编写一些多线程代码,因为您需要手动管理诸如关联id到原始线程的映射之类的内容(可能通过Futures)
这与ApacheCamel通过消息传递进行请求响应的方法类似。
需要注意的一件事是,当客户端这样做时,队列不会消失,因此您应该设置响应消息的生存时间,以便在没有消耗的情况下将其从代理中删除,否则您将得到未消耗的消息的积压。您还需要设置死信队列策略来自动丢弃过期邮件。