java - 使用线程隔离应用程序功能

标签 java jakarta-ee

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

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

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

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

最佳答案

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

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

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

<小时/>

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

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

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

<小时/>

更新:

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

关于java - 使用线程隔离应用程序功能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12487213/

相关文章:

java - 是否有像 "Set"这样的对象,它只能包含唯一的字符串值,但也包含对字符串值出现次数的计数?

java - 在 Java 中实现单例模式

java - 检查字符串值是否是一组整数

java - 在不重新启动 WebSphere 的情况下重新加载 java 类的最佳方法?

java - 无法使用 jdk8 和 netbeans 8 打开 Web 服务测试器页面

java - 在selelenium webdriver中,如何在pom运行失败的测试用例后配置邮件。将详细的程序清楚地发送给我

java - 如何迭代列出的元素数组,每次完成一组操作

java - 当客户端使用 readTimeout 关闭连接时服务器会发生什么

java - Maven 没有使用本地仓库

jakarta-ee - EJB 模块无法从 glassfish 上的另一个 EJB 模块找到类