【问题标题】:Tomcat: increase maxThreads without risking OutOfMemoryErrorTomcat:增加 maxThreads 而不会冒 OutOfMemoryError 的风险
【发布时间】:2013-06-28 09:50:17
【问题描述】:

我租了一个小型 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)。有没有更好的解决方案?

谢谢 danjoo

【问题讨论】:

    标签: java multithreading jsp tomcat out-of-memory


    【解决方案1】:

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


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

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

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

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

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

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


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

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

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

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

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

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

    【讨论】:

    • 感谢您提供非常详细的回复。向我展示了我应该仔细研究服务器应用程序的实际工作方式,并为我提供一些关于如何改进我的应用程序的想法!
    【解决方案2】:

    您应该在公式中添加堆栈大小。它取决于 JVM,例如对于 HotSpot,32 位 JVM 上每个线程的默认堆栈大小约为 512k。顺便说一句,像你说的这么小的内存量和 250 个线程堆栈大小可能是实际问题。请注意,您可以使用 -Xss 选项更改它。

    【讨论】:

    • 朱普。已经意识到 250 个线程可能有点太……热情了。这就是为什么我现在将其设置为 50。所以更好的公式是说 maxThreads = (threadMemory + 512k)/maxMemory ?公式不必是 100% 准确的。它必须让我知道该服务器上什么是可能的,什么不是(这样我可以决定是否需要移动到具有更大堆的服务器。)
    【解决方案3】:

    每个线程使用的内存量取决于您在线程中执行的操作。所以这取决于你的软件。

    计算起来没那么容易。

    但是 92MB 的 tomcat 非常紧凑。我会想办法解决这个问题。

    【讨论】:

    • 这就是为什么我想看看最大线程数是多少。如果我将线程设置为最大可能,我看看是否需要移动到具有更多堆的服务器。
    • @danjoo 我相信您可以在 tomcat 文档中找到理论上的最大值。但是如果你把它设置得太高,你的服务器将忙于上下文切换而不是工作。默认线程数通常很好(我相信 200)。如果这还不够,也许您应该考虑增加吞吐量。如果您接近内存限制,那么您的系统可能一直在收集。
    猜你喜欢
    • 2017-07-08
    • 2011-01-07
    • 1970-01-01
    • 2014-08-31
    • 2012-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多