如果没有可用的临时队列,实现请求/回复模式的最佳方式是啥?
Posted
技术标签:
【中文标题】如果没有可用的临时队列,实现请求/回复模式的最佳方式是啥?【英文标题】:What's the best way to implement a Request/Reply pattern if no temporary queues are available?如果没有可用的临时队列,实现请求/回复模式的最佳方式是什么? 【发布时间】:2011-06-18 12:13:44 【问题描述】:我的客户端应用程序有很多实例。这些客户端通过消息传递向服务器应用程序发送请求并接收回复。通常会使用临时队列发送回复。
不幸的是,我必须使用没有临时队列或主题概念的 Stomp 协议。 (虽然消息代理有)
确保只有原始请求者收到回复的最佳方法是什么?对于这种不幸的情况,有什么最佳做法吗?
【问题讨论】:
我想这将在很大程度上取决于您正在使用的技术(并且您没有提到)。 我想要一个与 JMS 兼容且与任何具体消息传递实现无关的解决方案。我本可以提到我正在使用 ActiveMQ,但我不想让我的应用程序依赖于只有 ActiveMQ 才能实现的东西。 @DR: stomp 协议几乎将你锁定在 ActiveMQ 中,不是吗?没有一个“真正的”企业 JMS 提供商使用它。 对于 WebSphere MQ,这不是问题。您只需将回复 JNDI 对象配置为指向模型队列。该应用程序不知道临时队列和预定义队列之间的区别。它只知道 JNDI 对象名称。我不熟悉其他供应商的实现,但他们中的大多数没有类似的东西吗? @T.Rob:问题更多:保证只有请求客户端收到响应而不是其他任何响应的最佳方法是什么。 【参考方案1】:当多个请求者在同一个队列上监听回复时,通常的解决方案是使用相关 ID 来选择消息。在客户端它看起来像这样:
-
在请求队列中放置一条消息并提交。
从出站消息中检索 JMSMessageID(该值由代理确定,并根据发送结果更新消息对象)。
从回复队列接收消息,指定出站消息中的 JMSMessageID 作为选择器中的相关 ID。
处理和提交。
在服务器端它看起来像这样:
-
在同步点下接收消息。
处理请求并准备响应。
将响应中的 JMSCorrelationID 设置为请求中 JMSMessageID 的值。
发送消息。
提交。
消费者会像这样设置选择器:activemq.selector:JMSCorrelationID=
。
由于代理创建的消息 ID 应该是全局唯一的,因此使用它作为关联 ID 的模式可以防止在允许每个请求者指定自己的值时可能发生的冲突。
【讨论】:
【参考方案2】:使用 JMS 实现此模式的最佳方法(无论如何我已经找到)是为响应消息创建一个预配置的主题,并在响应消息上使用相关选择器,以便客户端可以获得正确的一个。
更详细地说,这意味着在请求消息上设置一个随机 ID(使用setJMSCorrelationID()
),并将该消息放入请求队列中。该请求消息的使用者对其进行处理,创建响应消息,在响应消息上设置相同的相关 ID,并将其放在响应主题上。与此同时,客户端正在使用一个选择器表达式来监听响应主题,该选择器表达式指定了它所期望的相关 ID。
危险在于响应消息在客户端可以开始监听之前发送,尽管这可能不太可能。您可以尝试使用预先配置的队列而不是主题来响应响应,但我发现主题往往更可靠(我选择的 JMS 提供程序是 HornetQ - 您的里程可能会有所不同)。
所有这些都告诉我,JMS 非常不适合请求/响应模型。 API 只是不正确地支持它。这并不奇怪,因为这从来都不是 JMS 的用例。
计算网格(Terracotta、Gigaspaces、Infinispan 等)之类的东西可能会产生更好的结果,但这对您来说并不是一个真正的选择。
【讨论】:
虽然这种竞争条件不太可能发生,但您的应用程序通常可以接受吗?我主要在金融部门工作,所以我不习惯这些消息是一次性的,即使它很少发生。我很好奇这种模式的使用频率。 @T.Rob:我从未见过它发生,不,但我可以想象它会发生的高吞吐量场景。此外,这将取决于您的网络/VM 架构和 JMS 实现。以上是关于如果没有可用的临时队列,实现请求/回复模式的最佳方式是啥?的主要内容,如果未能解决你的问题,请参考以下文章
使用 ActiveMQ、Camel 和 Spring 实现请求-回复模式
Servicestack RabbitMQ:当 RabbitMqProducer 无法在 RPC 模式中重新声明临时队列时,无限循环填充死信队列