0

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

这个类将运行两个单独的线程;一个将侦听消息并将接收到的消息添加到 FIFO 队列中,第二个将处理来自队列的消息。这样做的原因是我不认为 AMQP 客户端会受到消息处理延迟的影响。

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

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

4

1 回答 1

2

在单独的线程中运行东西并不一定会让它们运行得更快。

在单机上运行的系统的吞吐量受到机器的处理带宽的限制;即内核的数量和速度、内存系统、磁盘和网络 I/O 等。在多线程应用程序中,所有线程都有效地共享资源。因此,例如,如果您在给定时刻拥有比核心更多的可运行线程,则某些线程将等待被调度到代码中。

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


那么这如何应用于您的系统呢?好吧,潜在的问题是正在执行后台处理的额外线程将使用资源,如果线程的工作过多: - 它们可能无法跟上,队列长度可能会超出控制,导致长时间的延迟甚至更糟,并且 - 这可能会干扰听众接受新消息的能力。

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

如果您认为您的系统可能会被更多可以处理的消息淹没,则需要对其进行设计以减轻负载;例如,通过停止接受新请求或转储现有请求。您不想要无限的队列或无限数量的工作线程,这些可能会导致灾难性的反馈和系统在重负载下崩溃/崩溃。(还要注意,由于未检测到的并发错误,重负载会导致更多的争用并增加失败的机会。)


更新:

  1. 似乎 AMQP 具有使用“流帧”的内置流控制机制。您可能应该尝试利用它,而不是在内部进行自己的流量控制/负载管理。
  2. 消息持久性本身无济于事。虽然您可以缓冲大量消息流量,但它无法帮助您处理消息生成和处理速率之间的不匹配。(持久性机制也会导致消息传输速率变慢,尽管这可能不是您关心的问题。)
  3. 对不同服务进行单独的处理阶段可以提高吞吐量,但另一方面是您有更多的消息传递开销。底线是这种分区减少而不是增加吞吐量。
  4. 如果您希望您的解决方案扩大规模,您需要对其进行设计,以便您可以复制您的服务器;例如,与其将新请求发送到一台服务器,不如将它们拆分到具有独立持久性后端的 N 台服务器上。
于 2012-09-19T01:31:56.063 回答