【问题标题】:Why would i only get ConcurrentModificationException only on 1 of three web servers that have the same exact ear deployed为什么我只能在部署了相同耳朵的三台 Web 服务器中的一台上获得 ConcurrentModificationException
【发布时间】:2020-05-20 10:01:23
【问题描述】:

我们在三个相同的 WebLogic 服务器上部署了 peoplesoft 应用程序。 netscaler 设备在它们之间进行负载平衡并保持会话粘性。交付的 Peoplesoft ear 应用程序由 Oracle 交付,我们没有以任何方式定制。

三个 Web 服务器之一出现 ConcurrentModificationExceptions。我们在整个企业的许多其他服务器上部署了相同的耳朵,但这是唯一遇到此问题的服务器。这个问题非常严重,以至于我们不得不让服务器停机并离开服务器场。所以现在我们在原来的 3 台服务器中的 2 台上进行负载平衡。

作为 Oracle 的客户,我们无权访问任何源代码。这使得缩小问题的范围变得困难。

由于这只耳朵与正常运行的服务器上的耳朵完全相同,我认为“差异”一定是导致问题的耳朵之外的东西。

这是我的发现:

当应用程序试图从 JOLT 连接池中获取线程时发生异常。该池由 java 链表对象管理。线程尝试遍历链表以寻找可用的连接来连接到应用服务器。 (背景:peoplesoft ear(部署在 WebLogic App Server 中)使用 JOLT 连接到另一层(由 C++ 和 java 代码组成的 App Server,通过 Tuxedo 控制的 IPC 对象(如队列、共享内存......)进行通信)。颠簸连接是池化以提高效率。线程在从池中分配连接之前失败。另一个线程(我假设)遍历链表,然后导致 ConcurrentModificationException。

一些线程能够成功地从 jolt 池中获得连接,但是当流量增加时,发生 ConcurrentModificationException 的可能性也会增加。

当我说我检查了某些东西时,我的意思是我将它们与服务器上的相同项目进行了比较而没有问题

我检查了很多东西以寻找原因:

  • 检查并重新安装 weblogic
  • 检查并重新安装 peopletools
  • 检查并重新部署 peoplesoft 应用程序
  • 检查并重新安装 java
  • 使用了不同版本的 java
  • 检查了类路径
  • 检查环境变量
  • 检查了 ulimits
  • 检查了 java 命令行选项
  • 检查了操作系统版本、技术级别和服务包版本
  • 检查了操作系统文件集

我对要检查的内容没有任何想法。

java.util.ConcurrentModificationException       java.util.ConcurrentModificationException<br>^M
        at java.util.LinkedList$ListItr.checkForComodification(LinkedList.java:977)^M
        at java.util.LinkedList$ListItr.next(LinkedList.java:899)^M
        at psft.pt8.net.JoltSessionPool.getJoltSession(JoltSessionPool.java:276)^M
        at psft.pt8.net.NetSession.getJoltSession(NetSession.java:693)^M
        at psft.pt8.net.NetReqRepSvc.sendRequest(NetReqRepSvc.java:556)^M
        at psft.pt8.net.NetService.requestService(NetService.java:167)^M
        at psft.pt8.net.NetReqRepSvc.requestService(NetReqRepSvc.java:354)^M
        at psft.pt8.jb.JBEntry.processRequest(JBEntry.java:673)^M
        at psft.pt8.psc.onActionGen(psc.java:3045)^M
        at psft.pt8.psc.onAction(psc.java:1753)^M
        at psft.pt8.psc.onAction(psc.java:1742)^M
        at psft.pt8.psc.service(psc.java:963)^M
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)^M
        at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:286)^M
        at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:260)^M
        at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:137)^M
        at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:350)^M
        at weblogic.servlet.internal.TailFilter.doFilter(TailFilter.java:25)^M
        at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:78)^M
        at weblogic.websocket.tyrus.TyrusServletFilter.doFilter(TyrusServletFilter.java:274)^M
        at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:78)^M
        at psft.pt8.psfilter.doFilter(psfilter.java:88)^M
        at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:78)^M
        at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.wrapRun(WebAppServletContext.java:3706)^M
        at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3672)^M
        at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:328)^M
        at weblogic.security.service.SecurityManager.runAsForUserCode(SecurityManager.java:197)^M
        at weblogic.servlet.provider.WlsSecurityProvider.runAsForUserCode(WlsSecurityProvider.java:203)^M
        at weblogic.servlet.provider.WlsSubjectHandle.run(WlsSubjectHandle.java:71)^M
        at weblogic.servlet.internal.WebAppServletContext.doSecuredExecute(WebAppServletContext.java:2443)^M
        at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2291)^M
        at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2269)^M
        at weblogic.servlet.internal.ServletRequestImpl.runInternal(ServletRequestImpl.java:1705)^M
        at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1665)^M
        at weblogic.servlet.provider.ContainerSupportProviderImpl$WlsRequestExecutor.run(ContainerSupportProviderImpl.java:272)^M
        at weblogic.invocation.ComponentInvocationContextManager._runAs(ComponentInvocationContextManager.java:352)^M
        at weblogic.invocation.ComponentInvocationContextManager.runAs(ComponentInvocationContextManager.java:337)^M
        at weblogic.work.LivePartitionUtility.doRunWorkUnderContext(LivePartitionUtility.java:57)^M
        at weblogic.work.PartitionUtility.runWorkUnderContext(PartitionUtility.java:41)^M

什么,在 java 耳朵之外会影响这个?

【问题讨论】:

  • 所有服务器是否运行完全相同的 Java 版本?
  • 是的,丹,所有三台服务器都运行完全相同的 java 版本。我做了很多事情来验证它们是否完全相同(除了 java -version)。我编写了一个脚本来爬取整个 java 部署并生成 in 下每个文件的消息哈希 (sha-1),然后在工作服务器上执行相同操作。然后我使用各种比较工具来寻找任何差异,但没有

标签: java multithreading linked-list iterator concurrentmodification


【解决方案1】:

ConcurrentModificationException 几乎总是一个编码错误。该代码未准备好运行多个线程或存在缺陷。不幸的是,这可能会随机发生,例如当两个线程尝试同时修改资源时。另一种情况是单个线程使用快速失败迭代器修改它当前正在迭代的资源。第二种情况的发生是可以预见的。

另一个线程(我假设)遍历链表,然后导致 ConcurrentModificationException。

另一个线程可能必须通过添加或删除元素来修改链表。这是编码疏忽。

  1. 您是否联系过为您提供 peoplesoft 的软件公司?他们需要修复他们的代码并确保psft.pt8.net.JoltSessionPool.getJoltSession(JoltSessionPool.java:276) 线程安全。
  2. 此服务器的另一个选项是仅使用单个工作线程运行它。 (针对 Java 程序进行了配置,因此它不会打开多个 Java 线程。)在软件开发人员修复他们的错误之前,这可能是一个临时解决方案。
  3. 验证 weblogic servlet 没有被错误配置,并且在不应该的情况下允许多个线程。 (也许 peoplesoft 代码不应该被多个线程竞争。)

为什么会在一台特定的服务器上发生这种情况?

如果它是负载平衡的,请考虑服务器是否由于其相对于 Web 服务用户的物理位置而获得了大部分负载。更多的活动会增加线程竞争的机会。

【讨论】:

  • 我已经联系了软件供应商 (Oracle/Peoplesoft),但由于他们无法重现该问题,因此他们并没有真正投入任何时间。此代码已部署在数以万计的公司中,并且在高需求/高使用率环境中运行没有问题。
  • 我考虑了一个概念,因为这是负载平衡字符串中的第一台服务器,它可能会比其他服务器获得更多的负载。但是,如果这是一个促成因素,那么我希望在我们从负载平衡器中删除第一台(有问题的)服务器后查看第二台服务器上的情况。最初有三台服务器都处理大约 33% 的流量。在我们移除坏服务器后,剩下的两台服务器处理了 50% 的流量,没有遇到同样的问题。
  • 另一种选择是您找到问题所在,如果您的许可证允许(例如使用 java dec 或 intelliJ)反编译他们的 jar,然后报告它以便更快地修复它。
  • 我不认为我们有反编译的权限,不幸的是
  • 这里有一个更新,我关闭了java pooling,concurrentmodificationexception消失了。当然,这不是修复,我们确信问题是在迭代 jolt 线程池时发生的,因此关闭池将是一个临时解决方法,而且确实如此。不幸的是,当池关闭时,我们的运行效率会降低,但至少它给了我们一些喘息的机会。我还是想试试关闭 JIT/AOT 编译看看有什么影响
【解决方案2】:

几件事:

我对要检查的内容没有任何想法。

服务器硬件怎么样。有没有可能是内存较少或 CPU 较少或较慢的服务器导致负载下的不同交互?

如果它从不在其他服务器上发生,那么就大错特错了。你有什么方法可以将硬盘从工作服务器复制到损坏的服务器上吗?在我看来,存在某种配置差异或其他东西。

另一个线程(我假设)遍历 LinkedList,然后导致 ConcurrentModificationException。

实际上,2 个线程可以迭代同一个 LinkedList。不好的是,如果在线程迭代列表时列表发生了变化。实际上更多单线程应用程序看到 CME。在导致迭代抛出的情况下,线程可以从列表中删除某些内容。

作为一个黑客,根据你的绝望程度,你可以在类路径上提供一个不同的 LinkedList 类并对其进行检测,或者甚至为其添加锁以理解甚至防止问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-16
    • 2011-02-24
    • 1970-01-01
    • 1970-01-01
    • 2012-03-29
    • 1970-01-01
    相关资源
    最近更新 更多