EhCache + JGroups выдают «Исключение при очистке очереди репликации: ноль» - PullRequest
1 голос
/ 10 февраля 2012

Я пытаюсь настроить 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-core версии 2.5.1, ehcache-jgroupsreplication версии 1.5.

Что я делаю не так?

ОБНОВЛЕНИЕ : При переходе на 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)

ОБНОВЛЕНИЕ 2 : В JIRA Terracota создана проблема: https://jira.terracotta.org/jira/browse/EHC-927

Ответы [ 2 ]

2 голосов
/ 14 февраля 2012

Как указал Крис в EHC927 Я использовал неправильный класс cacheEventListenerFactory. Это должно быть net.sf.ehcache.distribution.jgroups.JGroupsCacheReplicatorFactory вместо net.sf.ehcache.distribution.RMICacheReplicatorFactory.

1 голос
/ 11 февраля 2012

Я проверил исходный код класса 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. Так же, как и для проверки потока alive() в цикле while ...

Он не может очистить объект, если объект не существует или не инициализирован ... как он может знать, что объект пуст или нет, если он даже не существует или не инициализирован? Просто поймать 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);
        }
    }
}

Цель кода - просто избежать перехода времени простоя ЦП на 50%, когда поток ничего не делает в цикле while, что может заставить пользователя поверить, что с Encache что-то не так, если загрузка ЦП развивается примерно на 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();
}

Может быть, вы можете на время игнорировать проблему и позволить кому-то еще сообщить об ошибке, если она даже считается ошибкой ... Интересно, почему она говорит "Продолжение ..." позже ...

...