2012-02-10 309 views
1

我试图配置EhCache与基于JGroups的复制,但我得到日志充斥与第一个元素添加到缓存中的以下异常:EhCache + JGroups给出“关于复制队列清空异常:空”

12061 [Replication Thread] ERROR net.sf.ehcache.distribution.RMIAsynchronousCacheReplicator - Exception on flushing of replication queue: null. Continuing... 
java.lang.NullPointerException 
    at net.sf.ehcache.distribution.RMISynchronousCacheReplicator.listRemoteCachePeers(RMISynchronousCacheReplicator.java:335) 
    at net.sf.ehcache.distribution.RMIAsynchronousCacheReplicator.flushReplicationQueue(RMIAsynchronousCacheReplicator.java:299) 
    at net.sf.ehcache.distribution.RMIAsynchronousCacheReplicator.replicationThreadMain(RMIAsynchronousCacheReplicator.java:119) 
    at net.sf.ehcache.distribution.RMIAsynchronousCacheReplicator.access$100(RMIAsynchronousCacheReplicator.java:57) 
    at net.sf.ehcache.distribution.RMIAsynchronousCacheReplicator$ReplicationThread.run(RMIAsynchronousCacheReplicator.java:371) 

ehcache.xml中是这样的:

<?xml version="1.0" encoding="UTF-8"?>  
<ehcache 
    updateCheck="true" 
    monitoring="autodetect" 
    defaultTransactionTimeoutInSeconds="30" 
    dynamicConfig="true"> 

    <cacheManagerPeerProviderFactory 
    class="net.sf.ehcache.distribution.jgroups.JGroupsCacheManagerPeerProviderFactory" 
    properties="jgroups.xml" 
    /> 

    <defaultCache 
    maxElementsInMemory="200" 
    eternal="false" 
    statistics="true" 
    timeToIdleSeconds="86400" 
    timeToLiveSeconds="86400"  
    overflowToDisk="false">  
    <cacheEventListenerFactory 
     class="net.sf.ehcache.distribution.RMICacheReplicatorFactory" 
     properties="replicateAsynchronously=true, replicatePuts=true, replicateUpdates=true, replicateUpdatesViaCopy=true, replicateRemovals=true" 
    /> 
    <bootstrapCacheLoaderFactory class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory" />  
    </defaultCache> 

</ehcache> 

jgroups.xml是这样的:

<?xml version='1.0'?> 
<config> 
    <TCP start_port="7800" /> 
    <TCPPING 
     timeout="3000" 
     initial_hosts="localhost[7800],localhost[7800]" 
     port_range="10" 
     num_initial_members="2" /> 
    <VERIFY_SUSPECT timeout="1500" /> 
    <pbcast.NAKACK 
     use_mcast_xmit="false" 
     gc_lag="100" 
     retransmit_timeout="300,600,1200,2400,4800" 
     discard_delivered_msgs="true" /> 
    <pbcast.STABLE 
     stability_delay="1000" 
     desired_avg_gossip="50000" 
     max_bytes="400000" /> 
    <pbcast.GMS 
     print_local_addr="true" 
     join_timeout="5000" 
     shun="false" 
     view_bundling="true" /> 
</config> 

使用的JGroups版本2.8.1.GA,ehcache的核心版本2.5.1,ehcache的-jgroupsreplication版本1.5。

我在做什么错?

UPDATE:当我更改为replicateAsynchronously=false我得到以下异常:

Exception in thread "main" java.lang.NullPointerException 
    at net.sf.ehcache.distribution.RMISynchronousCacheReplicator.listRemoteCachePeers(RMISynchronousCacheReplicator.java:335) 
    at net.sf.ehcache.distribution.RMISynchronousCacheReplicator.replicatePutNotification(RMISynchronousCacheReplicator.java:145) 
    at net.sf.ehcache.distribution.RMISynchronousCacheReplicator.notifyElementPut(RMISynchronousCacheReplicator.java:132) 
    at net.sf.ehcache.event.RegisteredEventListeners.notifyListener(RegisteredEventListeners.java:294) 
    at net.sf.ehcache.event.RegisteredEventListeners.invokeListener(RegisteredEventListeners.java:284) 
    at net.sf.ehcache.event.RegisteredEventListeners.internalNotifyElementPut(RegisteredEventListeners.java:144) 
    at net.sf.ehcache.event.RegisteredEventListeners.notifyElementPut(RegisteredEventListeners.java:122) 
    at net.sf.ehcache.Cache.notifyPutInternalListeners(Cache.java:1515) 
    at net.sf.ehcache.Cache.putInternal(Cache.java:1490) 
    at net.sf.ehcache.Cache.put(Cache.java:1417) 
    at net.sf.ehcache.Cache.put(Cache.java:1382) 

更新2https://jira.terracotta.org/jira/browse/EHC-927

+0

解决方法是将最小堆大小设置为最大堆大小以在启动时强制堆分配,或者在堆增长时放置一些丢失的消息。 http://ehcache.org/apidocs/net/sf/ehcache/distribution/RMIAsynchronousCacheReplicator.html – ecle 2012-02-10 13:45:36

+0

设置为-Xmx500M -Xms500M,但仍然有同样的问题:( – 2012-02-10 13:59:39

+0

似乎复制队列根本没有初始化localhost [7800],localhost [7800]'This is ok?http://ehcache.org/documentation/replication/jgroups-replicated-caching – ecle 2012-02-10 14:58:01

回答

2

正如Chris在EHC927中指出的那样,我使用了错误的cacheEventListenerFactory类。它应该是net.sf.ehcache.distribution.jgroups.JGroupsCacheReplicatorFactory而不是net.sf.ehcache.distribution.RMICacheReplicatorFactory

+0

中指出的那样,这很明显:)这篇文章可以用来帮助他人解决同样的问题 – 2012-02-14 08:12:06

1

我检查的源代码:问题是陶土的JIRA创建for RMIAsynchronousCacheReplicator类

http://www.jarvana.com/jarvana/view/net/sf/ehcache/ehcache-core/2.1.0/ehcache-core-2.1.0-sources.jar!/net/sf/ehcache/distribution/RMIAsynchronousCacheReplicator.java?format=ok

有当flushReplicationQueue()被称为不对的东西;还应该检查replicationQueue != null,不只是replicationQueue.size() == 0。就像它在while循环中测试线程的alive() ...

如果对象不存在或未初始化,它无法刷新对象......它如何知道对象是空的还是不是如果它甚至不存在,或者未初始化?只要抓住NullPointerException是不是一个很好的方式告诉用户它!

/** 
* RemoteDebugger method for the replicationQueue thread. 
* <p/> 
* Note that the replicationQueue thread locks the cache for the entire time it is writing elements to the disk. 
*/ 
private void replicationThreadMain() { 
    while (true) { 
     // Wait for elements in the replicationQueue 
     while (alive() && replicationQueue != null && replicationQueue.size() == 0) { 
      try { 
       Thread.sleep(asynchronousReplicationInterval); 
      } catch (InterruptedException e) { 
       LOG.debug("Spool Thread interrupted."); 
       return; 
      } 
     } 
     if (notAlive()) { 
      return; 
     } 
     try { 
      if (replicationQueue.size() != 0) { 
       flushReplicationQueue(); 
      } 
     } catch (Throwable e) { 
      LOG.error("Exception on flushing of replication queue: " + e.getMessage() + ". Continuing...", e); 
     } 
    } 
} 

代码的目的只是为了避免CPU的空闲时间跳到50%,当线程什么也不做while循环,它可能会导致用户认为自己是不是有Encache如果CPU使用权一直演变50%左右...

可能需要将属性asynchronousReplicationInterval添加一个较小的值(100毫秒到150毫秒),以便可以构建复制队列。其追加如下:

properties="replicateAsynchronously=true, 
replicatePuts=true, 
replicateUpdates=true, 
replicateUpdatesViaCopy=true, 
replicateRemovals=true, 
asynchronousReplicationInterval=100" 

它可以在下面的RMIAsynchronousCacheReplicator构造需要:

/** 
* Constructor for internal and subclass use 
*/ 
public RMIAsynchronousCacheReplicator(
     boolean replicatePuts, 
     boolean replicatePutsViaCopy, 
     boolean replicateUpdates, 
     boolean replicateUpdatesViaCopy, 
     boolean replicateRemovals, 
     int asynchronousReplicationInterval) { 
    super(replicatePuts, 
      replicatePutsViaCopy, 
      replicateUpdates, 
      replicateUpdatesViaCopy, 
      replicateRemovals); 
    this.asynchronousReplicationInterval = asynchronousReplicationInterval; 
    status = Status.STATUS_ALIVE; 
    replicationThread.start(); 
} 

也许,你可以忽略暂时的问题,让如果别人报告的bug它甚至被认为是一个bug ......我想知道为什么它说“继续...”后来...

+0

问题是,异常充斥日志像疯了一样,现在我转向简单RMI代表而不是jgroups。 – 2012-02-11 20:17:43

+0

但是我会尝试一下你的建议asynchronousReplicationInterval – 2012-02-11 20:18:32

+0

仍然无法与asynchronousReplicationInterval = 100 :( – 2012-02-13 19:54:51