java 使用 JMS/ActiveMQ 并发同步请求-回复 - 模式/库?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11755146/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Concurrent Synchronous Request-Reply with JMS/ActiveMQ - Patterns/Libraries?
提问by joshwa
I have a web-app where when the user submits a request, we send a JMS message to a remote service and then wait for the reply. (There are also async requests, and we have various niceties set up for message replay, etc, so we'd prefer to stick with JMS instead of, say, HTTP)
我有一个 web 应用程序,当用户提交请求时,我们向远程服务发送一条 JMS 消息,然后等待回复。(还有异步请求,我们为消息重放等设置了各种细节,所以我们更愿意坚持使用 JMS 而不是 HTTP)
In How should I implement request response with JMS?, ActiveMQ seems to discourage the idea of either temporary queues per request or temporary consumers with selectors on the JMSCorrelationID, due to the overhead involved in spinning them up.
在我应该如何使用 JMS 实现请求响应?,ActiveMQ 似乎不鼓励每个请求的临时队列或在 JMSCorrelationID 上带有选择器的临时消费者的想法,因为旋转它们所涉及的开销。
However, if I use pooled consumers for the replies, how do I dispatch from the reply consumer back to the original requesting thread?
但是,如果我使用池消费者进行回复,我如何从回复消费者分派回原始请求线程?
I could certainly write my own thread-safe callback-registration/dispatch, but I hate writing code I suspect has has already been written by someone who knows better than I do.
我当然可以编写自己的线程安全回调注册/调度,但我讨厌编写我怀疑已经由比我更了解的人编写的代码。
That ActiveMQ page recommends Lingo, which hasn't been updated since 2006, and Camel Spring Remoting, which has been hellbanned by my team for its many gotcha bugs.
那个 ActiveMQ 页面推荐了Lingo,它自 2006 年以来就没有更新过,还有Camel Spring Remoting,它已经被我的团队禁止了,因为它有很多问题。
Is there a better solution, in the form of a library implementing this pattern, or in the form of a different pattern for simulating synchronous request-reply over JMS?
是否有更好的解决方案,以实现此模式的库的形式,或以不同模式的形式来模拟 JMS 上的同步请求-回复?
Related SO question:
相关问题:
- Is it a good practice to use JMS Temporary Queue for synchronous use?, which suggests that spinning up a consumer with a selector on the JMSCorrelationID is actually low-overhead, which contradicts what the ActiveMQ documentation says. Who's right?
- 使用 JMS 临时队列进行同步使用是一个好习惯吗?,这表明使用 JMSCorrelationID 上的选择器启动消费者实际上是低开销,这与 ActiveMQ 文档所说的相矛盾。谁是对的?
采纳答案by joshwa
A colleague suggested a potential solution-- one response queue/consumer per webapp thread, and we can set the return-address to the response queue owned by that particular thread. Since these threads are typically long-lived (and are re-used for subsequent web requests), we only have to suffer the overhead at the time the thread is spawned by the pool.
一位同事提出了一个潜在的解决方案——每个 webapp 线程一个响应队列/消费者,我们可以将返回地址设置为该特定线程拥有的响应队列。由于这些线程通常是长期存在的(并且被重新用于后续的 Web 请求),我们只需要在线程由池生成线程时承受开销。
That said, this whole exercise is making me rethink JMS vs HTTP... :)
也就是说,这整个练习让我重新思考 JMS 与 HTTP ... :)
回答by maasg
In a past project we had a similar situation, where a sync WS request was handled with a pair of Async req/res JMS Messages. We were using the Jboss JMS impl at that time and temporary destinations
where a big overhead.
在过去的项目中,我们遇到过类似的情况,同步 WS 请求是用一对 Async req/res JMS 消息处理的。当时我们正在使用 Jboss JMS impl,并且临时destinations
开销很大。
We ended up writing a thread-safe dispatcher, leaving the WS waiting until the JMS response came in. We used the CorrelationID to map the response back to the request.
我们最终编写了一个线程安全的调度程序,让 WS 等待 JMS 响应进来。我们使用 CorrelationID 将响应映射回请求。
That solution was all home grown, but I've come across a nice blocking map impl that solves the problem of matching a response to a request.
该解决方案都是自家开发的,但我遇到了一个很好的阻塞映射实现,它解决了将响应与请求匹配的问题。
If your solution is clustered, you need to take care that response messages are dispatched to the right node in the cluster. I don't know ActiveMQ, but I remember JBoss messaging to have some glitches under the hood for their clusterable destinations.
如果您的解决方案是集群的,您需要注意将响应消息分派到集群中的正确节点。我不知道 ActiveMQ,但我记得 JBoss 消息传递在其可集群目标的引擎盖下有一些小故障。
回答by Petter Nordlander
I would still think about using Camel and let it handle the threading, perhaps without spring-remoting but just raw ProducerTemplates.
我仍然会考虑使用 Camel 并让它处理线程,也许没有弹簧远程处理,而只是原始的 ProducerTemplates。
Camel has some nice documentation about the topic and works very well with ActiveMQ. http://camel.apache.org/jms#JMS-RequestreplyoverJMS
Camel 有一些关于该主题的不错的文档,并且与 ActiveMQ 配合得很好。 http://camel.apache.org/jms#JMS-RequestreplyoverJMS
For your question about spinning up a selector based consumer and the overhead, what the ActiveMQ docs actually states is that it requires a roundtrip to the ActiveMQ broker, which might be on the other side of the globe or on a high delay network. The overhead in this case is the TCP/IP round trip time to the AMQ broker. I would consider this as an option. Have used it muliple times with success.
对于关于启动基于选择器的消费者和开销的问题,ActiveMQ 文档实际上指出它需要到 ActiveMQ 代理的往返,该代理可能位于地球的另一端或高延迟网络。这种情况下的开销是到 AMQ 代理的 TCP/IP 往返时间。我会认为这是一种选择。已成功使用它多次。
回答by GullerYA
It's an old one, but I've landed here searching for something else and actually do have some insights (hopefully will be helpful to someone).
这是一个旧的,但我已经登陆这里寻找其他东西并且实际上确实有一些见解(希望会对某人有所帮助)。
We have implemented very similar use-case with Hazelcast being our chassis for cluster's internode comminication. The essense is 2 datasets: 1 distributed map for responses, 1 'local' list of response awaiters (on each node in cluster).
我们已经实现了非常相似的用例,Hazelcast 是我们用于集群节点间通信的机箱。本质是 2 个数据集:1 个用于响应的分布式映射,1 个“本地”响应等待者列表(在集群中的每个节点上)。
- each request (receiving it's own thread from Jetty) creates an entry in the map of local awaiters; the entry has obviously the correlation UID and an object that will serve as a semaphore
- then the request is being dispatched to the remote (REST/JMS) and the original thread starts waiting on the semaphore; UID must be part of the request
- remote returns the response and writes it into the responses map with the correlated UID
- responses map is being listened; if the UID of the newly coming response is found in the map of the local awaiters, it's semaphore is being notified, original request's thread is being released, picking up the response from the responses map and returning it to the client
- 每个请求(从 Jetty 接收它自己的线程)都会在本地等待者的地图中创建一个条目;该条目显然具有相关 UID 和一个将用作信号量的对象
- 然后请求被分派到远程(REST/JMS)并且原始线程开始等待信号量;UID 必须是请求的一部分
- 远程返回响应并将其写入具有相关 UID 的响应映射
- 正在收听响应图;如果在本地等待者的映射中找到新响应的 UID,则通知它的信号量,正在释放原始请求的线程,从响应映射中获取响应并将其返回给客户端
This is a general description, I can update an answer with a few optimizations we have, in case there will be any interest.
这是一般性描述,我可以通过一些我们的优化来更新答案,以防有任何兴趣。
回答by ams
I have always used CorrelationID for request / response and never suffered any performance issues. I can't imagine why that would be a performance issue at all, it should be super fast for any messaging system to implement and quite an important feature to implement well.
我一直将 CorrelationID 用于请求/响应,并且从未遇到任何性能问题。我无法想象为什么这会是一个性能问题,任何消息传递系统都应该非常快地实现,并且是一个非常重要的功能,可以很好地实现。
http://www.eaipatterns.com/RequestReplyJmsExample.htmlhas the tow main stream solutions using replyToQueue or correlationID.
http://www.eaipatterns.com/RequestReplyJmsExample.html有使用replyToQueue 或correlationID 的两个主流解决方案。