我正在两节点JBoss集群上运行大型Java EE 7应用程序,该集群最近已从JBoss EAP 6升级到JBoss EAP 7.0.4。间歇地,应用程序遇到访问变得非常缓慢的问题,直至难以访问应用程序为止。几分钟后,问题会自动解决,操作恢复正常。
线程转储分析表明,此事件是由以下行为引起的:
Flash
。这样,它会尝试更新会话,但是由于线程A 已经锁定了该会话,因此它处于 BLOCKED 状态。Flash
(用于 any 会话)的第1步和第2步是由于我们使用同步分布式Infinispan会话高速缓存而导致的,并且实际上并不会造成问题,因为锁定是针对一个用户会话的本地操作。但是,第3步非常有问题,因为对一个用户会话的阻止更新会突然影响所有用户。
所有线程C 的堆栈跟踪是相同的:
stackTrace:
java.lang.Thread.State:处于阻塞状态(在对象监视器上) com.sun.faces.context.flash.ELFlash.getFlash(ELFlash.java:318)
-等待锁定<0x00007ef80a75e260>( io.undertow.servlet.spec.ServletContextImpl )
现在这对我来说非常令人惊讶。为什么所有尝试获取JSF闪存的请求都会被ServletContext
阻止(该请求对应用程序全局是全局的)?可以在Mojarra ELFlash
源代码中找到原因(第318行包含synchronized
语句):
if (appMap.get(EnableDistributable.getQualifiedName()) != null) {
synchronized (extContext.getContext()) {
if (extContext.getSession(false) != null) {
SessionHelper sessionHelper = SessionHelper.getInstance(extContext);
if (sessionHelper == null) {
sessionHelper = new SessionHelper();
}
sessionHelper.update(extContext, flash);
}
}
}
简而言之,在Mojarra 2.2.x的开发过程中,开发人员decided在JSF Flash
在分布式环境中运行的情况下,{{1 }}状态需要存储在会话中(如果存在),以便可以跨集群复制。
虽然我不一定对此有疑问,但我有以下问题:
Flash
上进行同步的背后原因是什么?这似乎过于广泛,可能会阻止大量请求。ServletContext
?我已经仔细研究了源代码,但是除了从Flash
中删除<distributable/>
或可能取消设置web.xml
上下文参数之外,似乎找不到其他方法。对于我的用例,这两个选项的影响都太大了。更新
我已经在Mojarra问题跟踪器上发布了有关此行为的GitHub问题(#4376)。