如何从JMS读取和收集响应消息并使它们可用于正确的servlet线程?

时间:2013-03-03 22:02:11

标签: java multithreading servlets jms sonicmq

我们为异步JMS消息传递系统提供了一个同步HTTP请求 - 响应前端。

每个HTTPRequest的HTTP查询servlet在查询队列中创建相应的JMS消息。此查询由后端处理,并为此查询创建一些响应消息。在JMS中组织响应消息的接收是什么好方法,并确保它们到达正确的servlet线程,以便它可以制定HTTPResponse?

查询和响应是非事务性的,无需持久化。其中大多数是读取查询。如果在45秒内没有读取响应,则servlet会生成超时响应。然而,吞吐量很重要。我们需要处理越来越多的查询。该系统已有十年历史,必须保持运行两年左右。

我们正在使用SonicMQ。我们为所有响应创建了一个队列。 servlet容器与代理有一个连接,用于读取和写入。我们为每个登录用户生成一个侦听器线程(大约1500个并发)此线程有一个带有消息选择器的接收器,该消息选择器仅为该特定用户选择响应消息。一旦servlet线程发送了它的查询消息,它就会等待用户的监听器线程通知它它已经读取了响应。

我们曾经有一个由所有发件人和所有接收者共享的QueueSession。这实际上工作(!)虽然会议正式不是线程安全的。每个线程创建一个QueueSession(servlet线程和监听器线程)在某种程度上改善了性能,但事情仍然不太稳定,我们希望更好地组织事情。

我已尝试为每个用户会话创建一个临时队列,而不是使用带有消息选择器的单个队列,但这会大大减慢速度。

什么是更好/正确的组织方式?

1 个答案:

答案 0 :(得分:1)

我把它作为评论开始,但它有点增长。

根据您的描述,听起来每个请求至少需要两个线程,甚至可能更多。如果你已经有1500个并发用户,并且你的查询已经足够了,你需要将它们移植到其他节点,我会说你已经很好地进入了危险区域,因为有多少活动线程会在JVM没有大量的CPU /内存分配和一些严重的设置调整。

关于删除JMS的评论是因为从应用程序的servlet端开始,当一个简单的线程池同样适用于JMS时,你只是做了很多额外的工作来使JMS成为一个同步请求/响应机制。能够运行多个并发查询以响应HTTP请求。听起来JMS是后端接收工作请求的一种不错的方式,因此重大改写可能是不值得的。

我认为组织这个的更好方法是每个tomcat实例的一组消费者,而不是每个请求线程的消费者。每个Webhead都可以拥有自己的响应队列,或者在单个队列中使用MessageSelectors。然后,当请求进入时,发送请求JMS消息并为消费者留出一个回调呼叫线程的方式,就像呼叫者等待SynchronousQueuetake()一样。如果您必须等待多条消息来提供单个请求,则可以合并ConcurrentLinkedQueue以使用CountdownLatch删除响应,以便在收到响应时向请求线程发出信号。通过这种方式,你可以拥有一个相对较小的线程池,负责在它们进入时接收消息。我觉得应该有一些可以帮助你解决这个问题的东西,但我不能想到任何东西。

之后,如果您仍然发现性能有问题,您可以通过添加tomcat实例进行扩展,或者查看非阻塞IO以进行HTTP请求处理,将相同的策略应用于前门和后端:使用用于处理大量请求卷的小型线程池,其中等待占用每个请求线程模型中的大量线程。