Java 使用线程隔离应用程序功能

Java 使用线程隔离应用程序功能,java,jakarta-ee,Java,Jakarta Ee,我正在构建一个JavaEE应用程序,其中包含处理AMQP“主题”的功能。我的想法是创建一个通过javax.servlet.ServletContextEvent的contextInitialized方法初始化的侦听器类 这个类将运行两个独立的线程;一个将侦听消息并将接收到的消息添加到FIFO队列,另一个将处理来自队列的消息。原因是我不知道AMQP客户端会受到消息处理延迟的影响 在一个具有多个“侦听器”的复杂应用程序中,我最终可能会遇到大量线程运行异步任务。我没有足够的经验从体系结构的角度了解以这

我正在构建一个JavaEE应用程序,其中包含处理AMQP“主题”的功能。我的想法是创建一个通过
javax.servlet.ServletContextEvent
的contextInitialized方法初始化的侦听器类

这个类将运行两个独立的线程;一个将侦听消息并将接收到的消息添加到FIFO队列,另一个将处理来自队列的消息。原因是我不知道AMQP客户端会受到消息处理延迟的影响

在一个具有多个“侦听器”的复杂应用程序中,我最终可能会遇到大量线程运行异步任务。我没有足够的经验从体系结构的角度了解以这种方式将应用程序拆分为多个线程是否是一种合理的方法


也许每个消息都应该在其“自己的”线程中处理,而不是由队列进程处理。如果您对使用多线程管理应用程序流或我提出的方法有任何建议或指导,我们将不胜感激。

在不同的线程中运行东西并不一定能让它们运行得更快

在一台机器上运行的系统的吞吐量受到该机器的处理带宽的限制;i、 e.内核、存储系统、磁盘和网络i/O等的数量和速度。在多线程应用程序中,所有线程都有效地共享资源。因此,例如,如果在给定时刻,可运行线程多于内核,那么一些线程将等待调度到代码

第二个问题是线程通常需要相互通信和/或更新共享数据结构。这两者都需要某种同步。如果有很多这样的情况发生,那么同步可能会成为降低吞吐量的瓶颈


那么这如何应用到您的系统中呢?嗯,潜在的问题是,执行后台处理的额外线程将使用资源,如果线程的工作量过大: -他们可能无法跟上,队列长度可能会失控,导致长时间延迟和更糟的情况,以及 -这可能会干扰侦听器接受新消息的能力

从性能角度来看,您希望避免的一件事是线程过多。超过某一点(取决于应用程序),添加更多线程实际上会由于各种原因降低吞吐量。根据经验,尝试将线程数限制为内核数的1到2倍

如果您认为您的系统可能会被它可以处理的更多消息所淹没,那么需要对其进行设计,使其能够卸载;e、 g.停止接受新请求,或放弃现有请求。您不需要无限的队列或无限数量的工作线程,这可能会导致灾难性的反馈和系统在重载下崩溃/崩溃。(还要注意,重载将导致更多的争用,并增加由于未检测到的并发错误而导致失败的可能性。)


更新:

  • AMQP似乎有一个使用“流帧”的内置流控制机制。您可能应该尝试利用这一点,而不是在内部进行自己的流控制/负载管理
  • 消息持久性本身没有帮助。虽然您可以缓冲大量的消息流量,但它不会帮助您处理消息生成和处理速率之间的不匹配。(持久性机制也会导致较慢的消息传输速率,尽管这可能不是您关心的问题。)
  • 在不同的服务上执行不同的处理阶段可以提高吞吐量,但另一方面,您会有更多的消息传递开销。底线是,这种分区可以减少吞吐量,而不是增加吞吐量
  • 如果您想扩大解决方案的规模,您需要对其进行设计,以便能够复制您的服务器;e、 g.不要让新请求转到一台服务器,而是将它们拆分到具有独立持久性后端的N台服务器上

  • 谢谢你,这很有帮助-你提出了一些非常合理的观点。因此,在这种情况下,更好的方法可能是在单独的线程中运行AMQP客户机,但在消息到达时(而不是通过额外的线程)处理每个消息。我想这里的问题是保持消息处理尽可能高效。在消息服务器(RabbitMQ)中使用持久性也可能是一种缓冲方式?更一般地说,如果一个“应用程序”包括多个web服务、一个AMQP客户端和一些Quartz计划报告,则最好构建一组较小的“服务”(EJB)每个应用程序都提供功能的一个组件,而不是一个试图提供所有功能的大型应用程序。这种跨多台服务器部署服务应用程序的方式是一个性能问题。