Jetty如何处理Threads和ThreadPools,它使用了太多内存

LON*_* DO 3 java api jetty microservices server

让服务器微服务运行图:

应用程序线程图

但我监视发现,初始化 24 个线程,然后请求线程增加 32 个,处理线程时减少为 24 个线程。

关闭线程的过程很慢,释放内存也很慢!

如何改善这个问题?感谢您的观看。

Joa*_*elt 12

你的图表不正确。

Jetty 有一个线程池,用于所有操作。

线程就是线程就是线程。

选择器/接受器/请求/异步处理/异步读取/异步写入/websocket/代理/客户端/等之间没有区别。

根据最新统计,在 Jetty 9.4.30.v20200611 中,Jetty 中大约有 93 个不同的事物可以使用线程池中的线程,这完全取决于您的应用程序正在做什么、正在使用什么网络协议以及什么功能您决定使用的 Jetty 内的各种 API。

回到你的图表。

去掉连接队列,那个框就没有意义了。甚至不确定你想在那里记录什么。

当线程用于接受器目的时,它根本不参与请求/响应处理。它接受连接并将其交给托管选择器来处理该新连接的实际接受和后续选择器管理。

选择器不是线程。有一个使用线程的选择器管理器,它管理 NIO 层使用的选择器。

仅当您在具有超过 8 个专用于 Jetty 的核心的多核计算机上接近 60,000 个活动并发选择器事件时,配置超过 1 个选择器才有用。(不要错误地将并发连接等同于并发选择器事件,您可以轻松拥有 200,000 个并发连接,并发选择器事件最多为 16 个。您需要在生产中监视 JVM 以了解应用程序选择器负载的实际情况)

Jetty 使用“Eat What You Kill”线程执行策略,这意味着“线程池队列”并不像您的图表中那样简单(通过获取/推送)。

线程创建是一件昂贵的事情(就时间而言),因此它们会尽可能长时间地在池中保持活动状态。在正确调整的 JVM 上创建线程通常比 GC 操作花费更多时间。(是的,我们知道这是一个有争议的说法,但我们过去 20 年在许多不同机器、环境和 JVM 上的经验表明这始终是正确的,即使在像 OpenJDK 14 这样的现代 JVM 上也是如此)

线程池中的线程创建可能会突然发生,具体取决于负载。“负载”可以是新连接、连接上的总体流量,甚至可以是您对应用程序中的各种 API 提出的简单需求。

随着时间的推移,空闲线程的删除是有意逐步进行的,以减少和/或消除负载突发期间创建线程的极端成本。

Jetty 使用该org.eclipse.jetty.util.thread.ThreadPool接口与线程池一起工作。

每个ThreadPool都有ThreadPoolBudgetJetty 内的各种 API 参与以指示所需的操作线程要求。Jetty 中有许多 API,一旦您开始使用它们,它们就会自动触发需要“保留”X 个线程,以便ThreadPool始终可用于该 API。示例:您有一个新的 HTTP/2 连接,它将在物理连接的生命周期内将线程池上的“保留线程”计数增加 1(以处理各种子请求的 HTTP/2 会话),物理连接的存在并不意味着线程正在线程池中使用,只有当选择器和/或 API 使用触发它时,它才会正常使用线程池,使用当前可用的任何线程。这允许 ThreadPool 实现来管理对“保留线程”的需求。这确保始终有一个线程来处理 HTTP/2 会话和子请求的低级行为(在此示例中,最容易将物理连接视为其管理的 HTTP/2 会话的子选择器)。这种“保留线程”概念对于许多关键任务的正确操作至关重要,否则您会遇到线程匮乏和许多关键任务的情况。

您的应用程序所需的最小和最大线程数取决于应用程序的行为及其所经历的负载,而不是某些任意的启动配置。

根据org.eclipse.jetty.util.thread.ThreadPool您选择的实现,您可以选择不同的选项来调整它处理空闲线程和空闲线程删除等事务的方式。

QueuedThreadPool(Jetty 世界中最常用的ThreadPool)中,空闲超时控制池中的线程何时被标识为“空闲”和“适合停止”。

空闲线程清理将在每个空闲超时间隔一次删除 1 个空闲线程。

一般建议是,每次必须创建线程时,都会使应用程序更慢地向客户端生成响应。

想要调整 Jetty 中线程的开发人员的另一个争论点是单个线程和单个请求/响应交换之间绝对没有关系。单个请求/响应交换可以跨多个线程(有时是多个线程,具体取决于您选择使用的 API)进行处理。

尝试通过操纵线程池来控制请求/响应处理的任何内容将不起作用(例如尝试通过设置较低的最大线程数来限制活动并发请求的数量)。

还要注意应用程序中 ThreadLocal 的使用,它们确实有效,但您必须了解将其附加到的线程的范围,才能长期成功地使用它们。