【发布时间】:2023-03-18 02:24:01
【问题描述】:
目标
我的目标是更好地了解 Java EE 环境中的并发性以及如何更好地使用它。
一般问题
我们以典型的 servlet 容器(tomcat)为例。对于每个请求,它使用 1 个线程来处理它。线程池配置为,池中最多可以有 80 个线程。让我们也以简单的 webapp 为例 - 它在每个请求期间进行一些处理和数据库通信。
在高峰时间,我可以看到 80 个并行运行的线程(+ 几个其他基础设施线程)。我们还假设我在“m1.large”EC2 实例中运行它。
我不认为所有这些线程都可以真正在这个硬件上并行运行。所以现在调度程序应该决定如何更好地在它们之间分配 CPU 时间。所以问题是 - 在这种情况下调度程序开销有多大?如何在线程数量和处理速度之间找到合适的平衡点?
演员比较
在 4 核 CPU 上拥有 80 多个线程对我来说听起来并不健康。特别是如果它们中的大多数被某种 IO(数据库、文件系统、套接字)阻塞 - 它们只会消耗宝贵的资源。如果我们将请求从线程中分离出来,并且只有合理数量的线程(例如 8 个)并且只向它们发送处理任务,该怎么办?当然,在这种情况下,IO 也应该是非阻塞的,这样当我需要的一些数据可用时我会接收事件,如果我有一些结果,我会发送事件。
据我了解,Actor 模型就是这样。 Actor 不绑定到线程(至少在 Akka 和 Scala 中)。所以我有合理的线程池和一堆包含处理任务的邮箱的actor。
现在的问题是 - actor 模型在性能、调度程序开销和资源(RAM、CPU)消耗方面与传统的每请求线程模型相比如何?
自定义线程
我有一些请求(只有几个)需要花费太多时间来处理。我优化了代码和所有算法,添加了缓存,但仍然需要太多时间。但我明白了,该算法可以并行化。它很自然地适合演员模型——我只是将我的大任务分成几个任务,然后以某种方式聚合结果(如果需要)。但是在每请求线程模型中,我需要生成自己的线程(或创建我的小线程池)。据我所知,在 Java EE 环境中不建议这样做。而且,从我的角度来看,它并不自然地适合每个请求的线程模型。问题出现了:我的线程池大小应该有多大?即使我会在硬件方面使其合理,我仍然有这堆由 servlet 容器管理的线程。线程管理变得分散并变得疯狂。
所以我的问题 - 在每个请求线程模型中处理这些情况的最佳方法是什么?
【问题讨论】:
标签: concurrency jakarta-ee httprequest actor