JRun 线程池配置

JRun 线程池配置

我和我的团队在过去 6 个月的大部分时间里一直在努力保持集群 ColdFusion 应用程序的稳定性,但收效甚微。我们求助于 SF,希望找到一些 JRun 专家或新想法,因为我们似乎无法找到解决办法。

设置:
两个 ColdFusion 7.0.2 实例在 Windows Server 2003 下的 IIS 6 上与 JRun 4(带最新更新)集群。两个四核 CPU,8GB RAM。

问题:
时不时地,通常每周一次,其中一个实例会完全停止处理请求。它上面没有任何活动,我们必须重新启动它。

我们知道的是:
每次发生这种情况时,JRun 的错误日志总是充满 java.lang.OutOfMemoryError:无法创建新的本机线程。

在阅读了 Macromedia/Adobe 的 JRun 文档和许多令人困惑的博客文章后,我们或多或少将其缩小到实例的 jrun.xml 中不正确/未优化的 JRun 线程池设置。

我们的jrun.xml的相关部分:

<service class="jrun.servlet.jrpp.JRunProxyService" name="ProxyService">
    <attribute name="activeHandlerThreads">500</attribute>
    <attribute name="backlog">500</attribute>
    <attribute name="deactivated">false</attribute>
    <attribute name="interface">*</attribute>
    <attribute name="maxHandlerThreads">1000</attribute>
    <attribute name="minHandlerThreads">1</attribute>
    <attribute name="port">51003</attribute>
    <attribute name="threadWaitTimeout">300</attribute>
    <attribute name="timeout">300</attribute>
{snip}  
</service>

我上周启用了 JRun 的指标日志记录来收集与线程相关的数据。这是记录一周后的数据摘要。

平均值:

{jrpp.listenTh}       1
{jrpp.idleTh}         9
{jrpp.delayTh}        0
{jrpp.busyTh}         0
{jrpp.totalTh}       10
{jrpp.delayRq}        0
{jrpp.droppedRq}      0
{jrpp.handledRq}      4
{jrpp.handledMs}   6036
{jrpp.delayMs}        0
{freeMemory}      48667
{totalMemory}    403598
{sessions}          737
{sessionsInMem}     737

最大值:

{jrpp.listenTh}       10
{jrpp.idleTh}         94
{jrpp.delayTh}         1
{jrpp.busyTh}         39
{jrpp.totalTh}       100
{jrpp.delayRq}         0
{jrpp.droppedRq}       0
{jrpp.handledRq}      87
{jrpp.handledMs}  508845
{jrpp.delayMs}         0
{freeMemory}      169313
{totalMemory}     578432
{sessions}          2297
{sessionsInMem}     2297

我们现在可以尝试什么吗?

干杯!


编辑#1-> 我忘记提及的事情:Windows Server 2003 Enterprise w/ JVM 1.4.2(用于 JRun)

是的,最大堆大小约为 1.4GB。我们以前有过泄漏,但我们修复了它们,现在应用程序使用量约为 400MB,很少超过。最大堆大小设置为 1200MB,所以我们没有达到这个值。当我们确实有泄漏时,JVM 会崩溃,实例会自行重启。现在不会发生这种情况,它只是停止处理传入请求。

我们认为它与此博客文章后面的线索有关: http://www.talkingtree.com/blog/index.cfm/2005/3/11/NewNativeThread

抛出的 Java 异常类型为 OutOfMemory,但实际上并不是说我们用完了堆空间,只是说无法创建新线程。异常类型有点误导。

基本上,博客说 500 作为 activeHandlerThreads 可能太高了,但我的指标似乎表明我们远远没有达到这个数字,这让我们感到困惑。

答案1

好吧,在了解 JRun 配置细节之前,让我们先看一些更大的问题。

如果您在 JRun 错误日志中收到 java.lang.OutOfMemoryError 异常,那么,您的内存不足。请不要为此点赞 ;-)。您没有说您运行的是 32 位还是 64 位 Windows,但您确实说您有 8 GB 的 RAM,因此这会对答案产生一些影响。您运行的是 32 位还是 64 位 JVM(以及哪个版本)也会产生影响。因此,这些答案将帮助我们彻底解决这个问题。

无论如何,您的应用程序确实会耗尽内存。它耗尽内存的原因有以下一个或多个:

  1. 您的应用程序正在泄漏内存。您的应用程序使用的某些对象不断被引用,因此永远无法进行垃圾回收;或者更糟的是,每次请求时新建的某些对象永远被另一个对象引用,因此永远无法进行垃圾回收。在这方面,正确的 J2EE 会话处理可能特别棘手。
  2. 处理每个并发请求所需的内存量(在配置的并发请求级别)超出了 JVM 堆中可用的内存量。例如,您的堆大小为 1 GB,每个请求最多可使用 10 MB。您的应用服务器已调整为允许 150 个并发请求。(我知道这些数字太简单了)。在这种情况下,如果您在负载下遇到 100 个或更多并发请求(如果每个请求都使用了满足请求所需的最大内存量),那么您肯定会耗尽内存。

需要注意的其他事项:在 32 位 Windows 上,32 位 JVM 只能分配大约 1.4 GB 的内存。我不记得 64 位 Windows 上的 32 位 JVM 是否有小于任何 32 位进程的理论最大值 4 GB 的限制。

更新

我阅读了 TalkingTree 链接的博客文章以及该文章中链接的其他文章。我没有遇到过这种情况,但我确实有以下观察:JRUN 指标日志记录可能不会记录您在线程使用高峰期引用的“最大值”。我认为它以固定的、重复的间隔记录指标。这有利于向您展示应用程序平稳、平均的性能特征,但它可能无法在错误情况开始发生之前捕获 JRUN 的状态。

尽管不知道 JRUN 线程管理的内部工作原理,我仍然认为它确实内存不足。也许它不是因为您的应用需要在 JVM 堆上分配内存而没有可用内存,而是因为 JRUN 尝试创建另一个线程来处理传入请求,而支持另一个线程所需的堆内存不可用,所以它内存不足 - 换句话说,线程不是空闲的 - 它们也需要堆内存。

您的选择似乎如下:

  1. 减少应用程序在每个请求中使用的内存量,或者-
  2. 尝试降低 JRUN 配置中的线程调整参数的值,以使更多线程排队进行处理,而不是同时进入运行状态,或者-
  3. 减少 ColdFusion 管理器中的同时请求数(请求调整页面,字段“同时请求的最大模板数”)

无论您选择哪种方案,我认为有效的解决方案都是实验性的。您必须进行更改,然后查看它对应用程序有何影响。您有一个负载测试环境,对吗?

答案2

尝试减少最大堆大小。每个线程都需要本机资源(以及 Java 自己的资源)。可用的虚拟 AS 为 2GB;1.2GB 为堆保留。剩余 800MB 的一部分用于代码(Java 的文本段和所有必需的 DLL),然后是 JRE 及其依赖项所需的本机分配……以及线程:默认情况下,每个线程保留 1MB 的 AS(尽管实际上只提交了一个页面),100 个线程 = 100MB(仅用于堆栈)。现在在各个部分之间添加一些额外的空间,一些碎片……OOM ;-)

相关内容