Tomcat:增加 maxThreads 而不会出现 OutOfMemoryError 风险

dan*_*joo 5 java multithreading jsp tomcat out-of-memory

我租了一个小型 tomcat 服务器,通过 dailyRazor 上的 jsp 为 Android 应用程序提供 http-get 服务。最大 Java 堆为“最大内存:92.81 MB”。

maxThreads 的默认 tomcat 设置为 25。随着使用我的服务的用户数量的增长,我在黄金时间收到大量服务器的拒绝连接/超时(我认为这是因为线程池太小)。这就是为什么我将 maxThreads 增加到 250。在这个晚上,服务器崩溃了,向我显示了多个 java.lang.OutOfMemoryError 。250 对于小堆来说似乎有点重:p 我暂时将 maxThreads 减少到 50,这似乎很好,因为我没有再收到任何错误。

由于我对 tomcat 不太了解,我想询问一个好方法来找到正确的 maxThreads 数。我考虑查看一个线程的最大内存使用量。那么 maxThreads = (maxMemory / memoryOfOneThread)。有更好的解决方案吗?

谢谢达尼乔

Ste*_*n C 0

答案是没有什么好办法,AFAIK。或者更准确地说,没有什么比“尝试看看”更好的了。


但我回答的真正原因是指出您对问题和期望的理解中的一些缺陷。

  1. 线程不使用堆内存。或者至少不是直接的。

    线程的大部分内存使用量是线程堆栈。线程堆栈大小是可调的,并且具有特定于平台的默认值,最大可达 1Mb。

    但是...线程堆栈并未在 Java 堆中分配。它分配在堆外内存中。

  2. 如果您的系统在增加堆栈数量时由于 OOME 而崩溃,则堆使用情况是由于线程上运行的代码而不是线程本身造成的。(好吧,你可能知道这一点。)

  3. 如果您遇到请求被丢弃等问题,那么增加线程数通常不是解决方案。事实上,它很可能会使吞吐量变得更糟。


问题是,线程要执行,必须将其分配给处理器;即“核心”。您的 Tomcat 服务器可能有 2 或 4 个核心(我猜)。所以这意味着任何时候只能执行 2 或 4 个线程。拥有 25 个线程,这意味着当所有 25 个线程都处于活动状态时,它们大约获得核心 CPU 时间的 1/6。如果有 250 个活动线程(如果发生过的话),它们将获得 1/60 的核心。同时:

  • 每个请求都会创建一堆对象,在请求完成之前无法对这些对象进行垃圾收集。

  • 每个请求都可能会争夺数据库周期、磁盘 I/O 带宽、网络带宽等。

  • 根据应用程序的性质,数据结构/数据库行的争用可能会增加,从而导致线程上下文切换开销增加。

线程数量可以为您提供最佳请求吞吐量,这将是一个最佳点。如果您显着超过这个值,吞吐量(每秒完成的请求)将会下降,并且处理每个请求的平均时间将会增加。走得太远,系统就会停止运转。(OOME 是发生这种情况的一种方式。另一种方式是请求花费太长时间,导致客户端超时并停止等待响应。)

基本上,您的应用程序(经过优化调整后)将达到一定的平均吞吐率。如果您的实际请求率超过该值,那么最好的策略是处理您可以处理的请求,并快速删除其余的请求。删除请求可能看起来很糟糕,但它比另一种方法要好,后者需要很长时间才能响应,导致请求者超时并启动新的请求。