2017-02-19 22 views
2

我在生产环境中使用WebSphere 7.x版与2.1.0 ehcache的库中的问题。 Web容器的线程都在等待咨询或插入缓存。的Ehcache的ReentrantReadWriteLock在并发环境

这是此刻的转储时的所有Web容器线程被挂起:

NULL 
3XMTHREADINFO  "WebContainer : 11" J9VMThread:0x00000000C7C10300, j9thread_t:0x0000010043913FB0, java/lang/Thread:0x00000000507623F0, state:P, prio=5 
sun.misc.Unsafe.park(Native Method) 
java.util.concurrent.locks.LockSupport.park(LockSupport.java:182) 
java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:822) <2> 
java.util.concurrent.locks.ReentrantReadWriteLock$WriteLock.lock(ReentrantReadWriteLock.java:907) 
net.sf.ehcache.store.compound.Segment.put(Segment.java:402) 
net.sf.ehcache.store.compound.CompoundStore.put(CompoundStore.java:132) 
net.sf.ehcache.Cache.putInternal(Cache.java:1247) <2> 
org.springframework.cache.ehcache.EhCacheCache.put(EhCacheCache.java:70) 
xxx.yyy.fac.security.userdetails.GaiaLdapAuthoritiesPopulator.putElementCache(GaiaLdapAuthoritiesPopulator.java:466) <4> 
xxx.yyy.dgtp.gaiafrontend.core.filters.preauth.GaiaGrantedAuthoritiesWebAuthenticationDetails.buildDetails(GaiaGrantedAuthoritiesWebAuthenticationDetails.java:32) <1> 
org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter.doAuthenticate(AbstractPreAuthenticatedProcessingFilter.java:114) <1> 
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 
org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105) 
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 
org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87) 
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 
org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:184) <1> 
org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) <1> 
com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:190) 
com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:125) 
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:322) 
xxx.yyy.dgtp.gaiafrontend.core.web.filters.JsonDeserializerFilter.doFilterChain(JsonDeserializerFilter.java:109) <1> 
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 
xxx.yyy.dgtp.gaiafrontend.core.filters.userinfo.UserInfoFilter.followWithTheRequestChain(UserInfoFilter.java:106) <1> 
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 
xxx.yyy.dgtp.gaia.commons.web.filters.RequestResponseWrapperFilter.doFilter(RequestResponseWrapperFilter.java:69) 
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 
org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:83) 
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76) 
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 
xxx.yyy.dgtp.gaiafrontend.core.web.filters.ResponseHeadersFilter.doFilter(ResponseHeadersFilter.java:55) 
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 
org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:184) <1> 
org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) <1> 
com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:190) 
com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:125) 
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88) 
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76) 
com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:190) 
com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:125) <1> 
com.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter(WebAppFilterManager.java:908) 
com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:939) <1> 
com.ibm.ws.webcontainer.servlet.ServletWrapperImpl.handleRequest(ServletWrapperImpl.java:181) 
com.ibm.ws.webcontainer.webapp.WebApp.handleRequest(WebApp.java:3994) 
com.ibm.ws.webcontainer.webapp.WebGroup.handleRequest(WebGroup.java:276) 
com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:945) 
com.ibm.ws.webcontainer.WSWebContainer.handleRequest(WSWebContainer.java:1592) 
com.ibm.ws.webcontainer.channel.WCChannelLink.ready(WCChannelLink.java:191) 
com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:453) <3> 
com.ibm.ws.tcp.channel.impl.NewConnectionInitialReadCallback.sendToDiscriminators(NewConnectionInitialReadCallback.java:214) <1> 
com.ibm.ws.tcp.channel.impl.AioReadCompletionListener.futureCompleted(AioReadCompletionListener.java:175) 
com.ibm.io.async.AbstractAsyncFuture.invokeCallback(AbstractAsyncFuture.java:217) 
com.ibm.io.async.AsyncChannelFuture$1.run(AsyncChannelFuture.java:205) 
com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1660)  

我采用弹簧作为ehcache的一个抽象层和代码来获取/放在缓存编程有没有什么特别的。

缓存的配置如下:

@Bean 
    public EhCacheManagerFactoryBean cacheFactoryBean() { 

     EhCacheManagerFactoryBean ehCacheManagerFactoryBean = new EhCacheManagerFactoryBean(); 
     ehCacheManagerFactoryBean.setConfigLocation(new ClassPathResource("gaia-cache-ldap.xml")); 
     return ehCacheManagerFactoryBean; 

    } 

    @Bean 
    public CacheManager cacheManagerLdap() { 
     CacheManager cacheManager = new EhCacheCacheManager(cacheFactoryBean().getObject()); 
     return cacheManager; 

    } 

与访问缓存中的代码:

private void getMemberOfRecursive(String group, ConcurrentMap<String, String> groupsCollector) { 

     if (group != null) { 
      if (existInCache(group)) { 
       log.debug("Group: {} exist in cache. No query executing", group); 
       groupsCollector.put(group, group); 
       Set<String> groups = (Set<String>) getElementCache(group).get(); 
       for (String newGroup : groups) { 
        getMemberOfRecursive(newGroup, groupsCollector); 
       } 
      } else { 
       String cn = getCnFromDn(group); 
       String filter = MessageFormat.format(getFilterGroupRecursive(), cn); 
       String baseDN = group.substring(group.indexOf(",") + 1); 
       groupsCollector.put(group, group); 

       log.debug("Executing recursive query with baseDN: {} " + 
         " and filter {}: ", baseDN, filter); 
       Set<String> groups = 
         getLdapTemplate().searchForSingleAttributeValues(
           baseDN, filter, new String[]{}, getRetrievesAttributes()); 
       putElementCache(group, groups); 
       for (String newGroup : groups) { 
        getMemberOfRecursive(newGroup, groupsCollector); 
       } 
      } 

     } 

的Ehcache配置文件:

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="false" monitoring="autodetect"  dynamicConfig="true"> 
    <diskStore path="java.io.tmpdir" /> 
    <defaultCache maxElementsInMemory="3000" eternal="false" timeToIdleSeconds="1200" 
        timeToLiveSeconds="1200" overflowToDisk="true" maxElementsOnDisk="10000" 
        diskPersistent="false" diskExpiryThreadIntervalSeconds="120" 
        memoryStoreEvictionPolicy="LRU"/> 
    <cache name="groupsldap" maxElementsInMemory="3000" eternal="true" overflowToDisk="false" 
      memoryStoreEvictionPolicy="LRU"/> 

</ehcache> 
+0

您可以添加的Ehcache配置?如果可能的话,尝试升级到更新的版本,'2.1.0'很古老。 –

+0

这是我们有,但它必须评估版本的上升的可能性。目标是在执行更新之前真正知道它是否是该版本的修复程序。 –

+0

至少有一个线程必须持有锁。或者有两个不同的锁(两个不同的堆栈跟踪),然后可能导致死锁。它是不可能有挡在了同一个锁的所有线程(和线程转储可能会撒谎......他们不可靠的)。 – Henri

回答

0

最后,它是可能会重现生产错误。此错误似乎与至少在Active Directory组的用户中存在的跨组相关。此错误也没有跳过上周缓存启用,并能够更密切地观察,有的StackOverflowError在这种情况下造成的LDAP连接池与处于等待状态的线程被耗尽进行分析。

一旦发现,这是由于这个问题,包括解决,消除了以前访问过的团体,它在本地测试这个时间缓存被复制,我们有饱和与行为的Web容器的线程池类似于在生产中检测到的。