在群集环境中访问Mojarra JSF Flash时发生线程阻塞

时间:2018-07-11 03:39:48

标签: java jsf jboss infinispan mojarra

我正在两节点JBoss集群上运行大型Java EE 7应用程序,该集群最近已从JBoss EAP 6升级到JBoss EAP 7.0.4。间歇地,应用程序遇到访问变得非常缓慢的问题,直至难以访问应用程序为止。几分钟后,问题会自动解决,操作恢复正常。

线程转储分析表明,此事件是由以下行为引起的:

  1. 线程A 尝试写入会话缓存,但必须等待获取对缓存条目的锁定。它处于 TIMED_WAITING 状态。
  2. A 线程B 尝试获取同一会话的JSF Flash。这样,它会尝试更新会话,但是由于线程A 已经锁定了该会话,因此它处于 BLOCKED 状态。
  3. 尝试获取JSF Flash(用于 any 会话)的
  4. 所有 线程C 被放入 BLOCKED 状态,从而使应用程序无响应。

第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 }}状态需要存储在会话中(如果存在),以便可以跨集群复制。

虽然我不一定对此有疑问,但我有以下问题:

  1. 在全局Flash上进行同步的背后原因是什么?这似乎过于广泛,可能会阻止大量请求。
  2. 是否有任何方法可以更改此行为,特别是针对ServletContext?我已经仔细研究了源代码,但是除了从Flash中删除<distributable/>或可能取消设置web.xml上下文参数之外,似乎找不到其他方法。对于我的用例,这两个选项的影响都太大了。

更新

我已经在Mojarra问题跟踪器上发布了有关此行为的GitHub问题(#4376)。

0 个答案:

没有答案