0

我们有一个用于异步 JMS 消息系统的同步 HTTP 请求-响应前端。

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

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

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

我们曾经让所有发送者和所有接收者共享一个 QueueSession。这实际上有效(!)虽然会话正式不是线程安全的。每个线程创建一个 QueueSession(servlet 线程和侦听器线程)在一定程度上提高了性能,但事情仍然不太稳定,我们希望更好地组织事情。

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

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

4

1 回答 1

1

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

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

我对删除 JMS 的评论是因为从您的应用程序的 servlet 方面,您只是在做很多额外的工作以使 JMS 成为一个同步请求/响应机制,而一个简单的线程池也可以为能够运行提供服务多个并发查询以响应 HTTP 请求。不过,听起来 JMS 是后端接收工作请求的一种不错的方式,因此可能不值得进行重大重写。

我认为组织这个的更好方法是每个 tomcat 实例的一组消费者,而不是每个请求线程的消费者。每个 webhead 都可以有自己的响应队列,或者在单个队列上使用 MessageSelector。然后当请求进来时,发送请求 JMS 消息并为消费者留出回调调用线程的方式,就像调用者正在等待从中获取()的SynchronousQueue。如果您必须等待多条消息来服务单个请求,则可以将ConcurrentLinkedQueue与CountdownLatch结合使用以丢弃响应在收到所有响应时向请求线程发出信号。这样,您可以拥有一个相对较小的线程池来负责在消息进来时接收消息。我觉得应该有一些东西可以帮助您解决这个问题,但我想不出任何手边的东西。

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

于 2013-03-04T02:26:07.863 回答