我正在使用JProfiler和JConsole对Grails Web应用程序进行概要分析,并观察到一种我无法完全理解的现象。
我正在分析的设置如下:
应用程序几乎每个请求都会调用Solr。没有数据库,也没有其他后端交互。 Ehcache用于缓存。
我创建了一组针对应用程序触发的中等负载测试。我已经为我的本地设置找出了一种负载限制。低于该限制,我对Grails应用程序进行了以下观察:
当我将负载提高超过上限时,图像会发生剧烈变化:
现在虽然完全可以理解在高负载下事情变慢但我非常担心超出负载限制锁定争用的事实并且花费了大量时间来阻塞。我调查了监视器的历史记录,特别是发现了很多与以下类似的事件:
org.apache.catalina.loader.WebappClassLoader
过滤了拥有线程的堆栈跟踪
groovy.lang.GroovyClassLoader.loadClass(java.lang.String)
Script1.$createCallSiteArray()
Script1.$getCallSiteArray()
Script1.__$swapInit()
Script1.<clinit>()
groovy.lang.Script$evaluate.callCurrent(groovy.lang.GroovyObject, java.lang.Object)
gsp_some_gsp_gsp.run()
org.codehaus.groovy.grails.web.pages.GroovyPagesTemplateRenderer.render(...)
Script1.call(java.lang.Object, java.lang.Object[ ])
org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(...)
等待线程的过滤堆栈跟踪:
groovy.lang.Script$evaluate.callCurrent(groovy.lang.GroovyObject, java.lang.Object)
gsp_some_gsp_gsp.run()
org.codehaus.groovy.grails.web.pages.GroovyPagesTemplateRenderer.render(...)
Script1.call(java.lang.Object, java.lang.Object[ ])
org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(...)
gsp_some_other_gsp_gsp$_run_closure2_closure5.doCall()
org.codehaus.groovy.grails.web.taglib.GroovyPageTagBody.call()
java_util_concurrent_Callable$call$53.call(java.lang.Object)
org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(...)
另一个观察结果(无论负载限制如何)是,加载类的总数不断增加。 (也会发生常规类卸载,因此到目前为止PermGen不是问题,但似乎不断生成新类。)
我的问题是为什么会发生WebappClassLoader上的这种阻塞。这种正常行为是否超过负载限制阻塞线程堆叠的事实只是机器过载的标志?这与Groovy或Grails或Tomcat类加载有关吗?有什么可以做的吗?
有关该系统的一些其他详细信息:
java version "1.7.0_51"
OpenJDK Runtime Environment (IcedTea 2.4.4) (7u51-2.4.4-0ubuntu0.12.04.2)
OpenJDK 64-Bit Server VM (build 24.45-b08, mixed mode)
Grails version 2.3.4
Groovy version 2.1.9
Ehcache 2.4.6
Tomcat version 7.0.26
Ubuntu 12.04
curl-loader for load tests
答案 0 :(得分:1)
可以通过升级到Tomcat 8.0.16或更高版本并将Loader类设置为org.apache.catalina.loader.ParallelWebappClassLoader来解决此问题。
在[TOMCAT_HOME] /conf/context.xml中,添加以下行并重新启动
<Loader loaderClass="org.apache.catalina.loader.ParallelWebappClassLoader" />
我们遇到了类似的问题,Hibernate和Spring JDBC会尝试将db结果集行转换为对象。这种锁定行为严重影响了tomcats运行大量具有大型结果集的线程,除了重启之外别无选择。使用Tomcat8的上述设置解决了这个问题。
我建议在Tomcat7上运行应用程序的用户在启用ParallelWebappClassLoader的情况下升级到Tomcat 8,以获得更好的性能。