我们在三个相同的WebLogic服务器上部署了一个peoplesoft应用程序。netscaler设备在它们之间实现负载平衡,并保持会话粘性。交付的Peoplesoft ear应用程序由Oracle提供,而不是由我们以任何方式进行定制。
三个web服务器中的一个显示ConcurrentModificationException。我们在整个企业的许多其他服务器上都部署了相同的ear,但这是唯一一个遇到此问题的服务器。这个问题非常严重,我们不得不关闭服务器并将其排除在服务器场之外。因此,现在我们在原来的3台服务器中的2台上实现负载平衡。
作为Oracle的客户,我们无法访问任何源代码。这使得缩小问题范围变得困难。
由于这个耳朵与正常工作的服务器上的耳朵完全相同,我认为"差异"一定是耳朵之外的东西导致了问题。
以下是我发现的:
当应用程序试图从JOLT连接池获取线程时,会发生异常。该池由一个java链表对象管理。线程尝试在链表上进行迭代,以寻找可用的连接来连接到应用程序服务器。(背景:peoplesoftear(部署在WebLogic应用服务器中)使用JOLT连接到另一层(由C++和java代码组成的应用服务器,通过Tuxedo控制的IPC对象(如队列、共享内存…)进行通信)。为了提高效率,将震动连接汇集在一起。线程在从池中分配连接之前失败。另一个线程(我假设)在linkedlist上迭代,然后导致ConcurrentModificationException。
一些线程能够成功地从震动池中获得连接,但当流量增加时,可能会发生ConcurrentModificationException。
当我说我检查了一些东西时,我的意思是我将它们与服务器上的相同项目进行了比较,没有问题
我检查了很多东西来寻找原因:
- 已检查并重新安装weblogic
- 已检查并重新安装人员工具
- 已检查并重新部署peoplesoft应用程序
- 检查并重新安装java
- 使用了不同版本的java
- 已检查类路径
- 已检查环境变量
- 检查了ulimits
- 检查了java命令行选项
- 已检查操作系统版本、技术级别和service Pack版本
- 检查了操作系统文件集
我不知道该检查什么了。
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 ear之外会影响这一点?
ConcurrentModificationException几乎总是一个编码错误。该代码没有为多个正在运行的线程准备,或者存在缺陷。不幸的是,这种情况可能是随机发生的,例如当两个线程试图同时修改一个资源时。另一种情况是,单个线程使用故障快速迭代器修改当前正在迭代的资源。第二种情况可以预见。
另一个线程(我认为)在linkedlist上迭代,然后导致ConcurrentModificationException。
另一个线程可能需要通过添加或删除元素来修改linkedlist。这是一个编码疏忽
- 您是否联系了为您提供peoplesoft的软件公司?他们需要修复自己的代码并使
psft.pt8.net.JoltSessionPool.getJoltSession(JoltSessionPool.java:276)
线程安全 - 该服务器的另一个选项是只使用一个工作线程来运行它。(为Java程序配置,这样它就不会打开多个Java线程。)在软件开发人员修复错误之前,这可能是一个临时解决方案
- 验证weblogic servlet没有被错误配置,并且在不应该被允许的时候允许多个线程。(也许peoplesoft代码不应该被多个线程争用。)
为什么会在一个特定的服务器上发生这种情况?
如果它是负载平衡的,请考虑服务器是否由于其相对于web服务用户的物理位置而获得了大部分负载。更多的活动将增加线程竞争的机会。
两件事:
我对该检查什么已经没有主意了。
服务器硬件怎么样。有没有可能是一个内存较少或CPU较少或较慢的服务器在负载下导致不同的交互?
如果它从未发生在其他服务器上,那么就出现了非常错误的情况。你有办法把硬盘驱动器从工作的服务器复制到坏的服务器上吗?在我看来,存在某种配置差异或其他什么。
另一个线程(我认为)在LinkedList上迭代,然后导致ConcurrentModificationException。
实际上,两个线程在同一个LinkedList
上迭代是可以的。不好的是,如果列表在线程对其进行迭代时发生了变化。实际上,单线程应用程序看到CME的情况更为典型。在可能导致迭代抛出的情况下,线程可以从列表中删除某些内容。
作为一个黑客,根据你的绝望程度,你可以在类路径上提供一个不同的LinkedList
类,并对其进行检测,甚至为其添加锁,以了解甚至防止问题的发生。