【问题标题】:ActiveMQ: How to handle broker failovers while using temporary queuesActiveMQ:如何在使用临时队列时处理代理故障转移
【发布时间】:2011-09-19 22:23: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. 我已经在 J​​MSCorrelationID 标头中发送了每条消息的唯一相关标识符。
  3. 据我所知,甚至 Camel 和 Spring 也在使用临时队列来实现请求-响应机制。唯一的区别是 Spring JMS 实现为每条消息创建和销毁临时队列,而我为生产者的生命周期创建临时队列。当客户端(生产者)应用关闭时,此临时队列将被销毁,或者当 AMQ 代理意识到此临时队列没有附加活动生产者时,它会被销毁。
  4. 我已经在 Producer 端为每条消息设置了消息过期时间,这样消息就不会在队列中等待太久(60 秒)。

【问题讨论】:

  • 新的JMSException 是刚刚登录还是扔到您的客户端代码中?此外,客户端发送给代理的每条消息都会引发异常,还是在故障转移完成时异常停止? (即异常是否只在客户端未连接时抛出?)
  • 除了jms.watchTopicAdvisories=false(即XML 配置中的<broker advisorySupport="false">)和静态配置网络之外,还有一些seems to be 需要做的事情。 (你的 amq1.xml 文件给了我一个 404 Not Found)
  • @Bringer128:感谢您的评论。该 JMS 异常会在生产者重新连接后连接的其他 AMQ 代理上引发。一旦发生这种情况,JMS 生产者将停止接收来自消费者的任何响应,因为 AMQ 代理无法将回复发送回具有上述 JMS 异常的生产者。
  • @opyate:感谢您的建议。然而,只是为了让您知道advisorySupport="false" 临时目的地在当前的 AMQ5.5 版本中不起作用,即使使用staticallyIncludedDestinations。但是,根据我的要求,此功能已在即将发布的 5.6 版本中添加。请在此处查看我与 Gary Tully 的对话:activemq.2283324.n4.nabble.com/… 了解更多详情

标签: java jms activemq failovercluster


【解决方案1】:

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

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

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

【讨论】:

  • 如果你注意到我在我的问题中写道:Whenever I restarted an arbitrary broker in my network。所以我想知道如果代理本身正在重新启动,这个代理属性cacheTempDestinations会有什么影响吗?
  • 当您重新启动代理时,任何临时目标以及任何待处理的消息都将丢失。代理没有为临时目的地维护持久状态。
  • 我们能做的最好的事情是:1)支持故障转移:重新连接到现有的代理。 2) 如果代理之间的网络分区或代理在发送对临时目标的回复之前发生故障,则允许自动创建临时目标。
  • 我已经在我的 JMS 客户端的 URL 中使用 failover: 连接到 AMQ 集群。当您写allow the temp destination to be auto created 时:您的意思是在某个随机代理死亡的情况下允许在其中一个实时代理上自动创建临时目标吗?我的问题是如何获得这个临时目标自动创建?
  • 添加了代理属性 allowTempAutoCreationOnSend 以支持AMQ-3253
【解决方案2】:

临时队列是在请求-回复场景中的请求者(生产者)所连接的代理上创建的。它们是从javax.jms.Session 创建的,因此在该会话断开连接时,无论是由于客户端断开连接还是代理故障/故障转移,这些队列都将永久消失。当您的一个消费者尝试回复这些队列时,其他代理都不会理解这意味着什么;因此你的例外。

假设您想要处理故障转移并保留所有消息,这需要在架构上转变思维方式。这是解决问题的一般方法:

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

这与Apache Camelrequest-response over messaging 采取的方法类似。

需要注意的一点是,当客户端消失时,队列不会消失,因此您应该设置一个时间来处理响应消息,这样如果它没有被消费,它就会从代理中删除,否则你会得到一堆未使用的消息。您还需要设置dead letter queue strategy to automatically discard expired messages

【讨论】:

  • 感谢您的详细解答。我在我的问题中添加了一个更新部分,以回应您的所有观点。您是否有机会建议我不要为每个生产者使用临时队列
  • 没错,临时队列不是为故障转移而设计的——它们是客户端和代理之间通过会话签订的合同;会话位于单独的连接上。默认情况下,Camel 确实通过临时队列进行请求-回复,但由于上述原因,这通常是不切实际的,因此支持静态队列作为满足服务质量的后备(尽管它使用 JMS 选择器而不是队列进行关联,这应该出于性能原因应避免使用)。
  • IMO 假设 temporary queues are not designed for failover 是不正确的。此外,如果不使用临时队列,那么当您事先不知道所有生产者时,您如何拥有a queue specific to the requestor process 或换句话说每个生产者。
  • 如果你真的走这条路,请求者应该以不冲突的方式命名他们监听的队列。如果您的请求者与 GUI 实例或主机名(如果您的请求者是服务器)相关联(我已经看到使用这两种方法),您可能会使用 uuid 和实际用户 ID 的组合 - 诀窍是确保队列名称是唯一的。
  • 如果您注意到所有这些都是临时队列的特征。而且如果每个生产者都开始创建唯一命名的队列,如果生产者突然死亡,他们将如何清理?
猜你喜欢
  • 2015-06-27
  • 1970-01-01
  • 2016-06-30
  • 1970-01-01
  • 2012-06-08
  • 1970-01-01
  • 2013-08-26
  • 1970-01-01
  • 2015-08-17
相关资源
最近更新 更多