我应该怎么做才能 bootstrap 从集群缓存对等方缓存?

What should i do so that i can bootstrap caches from cluster cache peer?

一共有三台服务器,都部署了ehcache。一台服务器由于某些原因正常或异常关闭,当我重新启动它时,我发现缓存变空并且数据丢失。当我检查时另外两台服务器,他们的缓存也变空了,数据也丢失了。我在 ehcach.org/community/ 上问过这个问题,但没有回复。我在 ehcache.org(http://www.ehcache.org/documentation/EhcacheUserGuide-1.6.pdf) 中搜索了好几天的答案,但我仍然不知道为什么。我只是找到了下面的字,但它并没有告诉我如何去做我仍然无法避免上述情况。

When a peer comes up, it will be incoherent with other caches. When the bootstrap completes it will be partially coherent. Bootstrap gets the list of keys from a random peer, and then loads those in batches from random peers. If bootstrap fails then the Cache will not start (not like this right now). However if a distributed cache operation occurs which is then overwritten by bootstrap there is a chance that the cache could be inconsistent.

下面是我的ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>    
<ehcache updateCheck="false">
    <diskStore path="java.io.tmpdir"/>
    <cacheManagerPeerListenerFactory class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory" properties="hostName=192.168.4.245, port=7800, socketTimeoutMillis=120000"/>
    <cacheManagerPeerProviderFactory class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory" properties="peerDiscovery=manual, rmiUrls=//192.168.4.250:7800/configInfoCache"/>
    <defaultCache maxElementsInMemory="10000" eternal="false" overflowToDisk="true" timeToIdleSeconds="0" timeToLiveSeconds="0" diskPersistent="false" diskExpiryThreadIntervalSeconds="120"> </defaultCache>
    <cache name="configInfoCache" maxElementsInMemory="10000" eternal="true" overflowToDisk="false" timeToIdleSeconds="0" timeToLiveSeconds="0" memoryStoreEvictionPolicy="LFU">
        <cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"/>
        <bootstrapCacheLoaderFactory class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory"/>
    </cache>
</ehcache>

ehcahe 版本 1.6.2 jdk 版本 1.6 tomcat6.0.44

希望有人告诉我该怎么做,在 ehcache.xml 中配置或实现 一些 interfaces.I 在此 question.please 上花费了很多时间!!!帮助我!!!

ps: 第一次在Whosebug上提问,有什么需要的可以私信我

你基本上有 2 个问题 - 首先,其他 运行 缓存在非一致性缓存启动时变空,其次 新启动的非一致性缓存不会自动与其他 运行 缓存同步。让我试着一一解决。

其他 运行 个缓存在非一致性缓存启动时变空

Ehcache 有几个属性定义缓存之间的同步将如何发生,这些属性定义缓存是否应该通过复制或失效复制到其他缓存。参考this。因此,基本上您需要将 Ehcache 配置为“通过复制复制”而不是“通过失效复制”。一旦你解决了这个问题,你的第一个问题就会得到解决。

为了便于参考,我输入了您应该使用的值(我在我的应用程序中使用了相同的配置):

##########  EhCache related properties ##########
peerDiscoveryMechanism=manual
replicatePuts=true
replicatePutsViaCopy=true
replicateUpdates=true
replicateUpdatesViaCopy=true
replicateRemovals=true
replicateAsynchronously=false

现在,您可以通过多种方式进行设置,我可以告诉您我是如何完成的。我已将它们放在一个属性文件中并加载它并在我的应用程序中使用。基本上你需要在 Echache 的 RMICacheReplicatorFactory 中配置这些并将其用作你的缓存 cacheEventListenerFactory。所以,我在 ehcache.xml

中定义了以下配置
<cache name="itdTestResultsCache" maxElementsInMemory="100000" eternal="true" overflowToDisk="false">
    <cacheEventListenerFactory class="com.cgi.itd.customComponents.serverCache.ItdRMICacheReplicatorFactory" />
</cache>

然后我的习惯ItdRMICacheReplicatorFactory class如下。请注意,它有加载属性然后使用它的代码 - String replicatePutsString = ITDPropertyPlaceholderConfigurer.getPropertiesMap().get(ITDApplicationConstants.REPLICATE_PUTS);,我不会给你那段代码,你可以硬编码或自己编写。

import java.util.Properties;

import net.sf.ehcache.distribution.RMICacheReplicatorFactory;
import net.sf.ehcache.util.PropertyUtil;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.cgi.itd.customComponents.ITDPropertyPlaceholderConfigurer;
import com.cgi.itd.utils.ITDApplicationConstants;

/**
 * Custom handler for RMI replicator factory
 * @author himanshu.agrawal
 *
 */
public class ItdRMICacheReplicatorFactory extends RMICacheReplicatorFactory {
    Log log = LogFactory.getLog(ItdRMICacheReplicatorFactory.class);

    public ItdRMICacheReplicatorFactory() {
        log.info("ItdRMICacheReplicatorFactory constructor.");
    }

    /**
     * Extracts the value of asynchronousReplicationIntervalMillis. Sets it to 1000ms if
     * either not set or there is a problem parsing the number
     * @param properties
     */
    @Override
    protected int extractReplicationIntervalMilis(Properties properties) {
        int asynchronousReplicationIntervalMillis;
        String asynchronousReplicationIntervalMillisString = ITDPropertyPlaceholderConfigurer.getPropertiesMap().get(ITDApplicationConstants.ASYNCHRONOUS_REPLICATION_INTERVAL_MILLIS);
        if (asynchronousReplicationIntervalMillisString != null) {
            try {
                int asynchronousReplicationIntervalMillisCandidate =
                        Integer.parseInt(asynchronousReplicationIntervalMillisString);
                if (asynchronousReplicationIntervalMillisCandidate < ITDApplicationConstants.MINIMUM_REASONABLE_INTERVAL) {
                    log.debug("Trying to set the asynchronousReplicationIntervalMillis to an unreasonable number." +
                            " Using the default instead.");
                    asynchronousReplicationIntervalMillis = DEFAULT_ASYNCHRONOUS_REPLICATION_INTERVAL_MILLIS;
                } else {
                    asynchronousReplicationIntervalMillis = asynchronousReplicationIntervalMillisCandidate;
                }
            } catch (NumberFormatException e) {
                log.warn("Number format exception trying to set asynchronousReplicationIntervalMillis. " +
                        "Using the default instead. String value was: '" + asynchronousReplicationIntervalMillisString + "'");
                asynchronousReplicationIntervalMillis = DEFAULT_ASYNCHRONOUS_REPLICATION_INTERVAL_MILLIS;
            }
        } else {
            asynchronousReplicationIntervalMillis = DEFAULT_ASYNCHRONOUS_REPLICATION_INTERVAL_MILLIS;
        }
        log.debug("Extracted asynchronousReplicationIntervalMillis = " + asynchronousReplicationIntervalMillis);
        return asynchronousReplicationIntervalMillis;
    }

    /**
     * Extracts the value of replicateAsynchronously from the properties
     * @param properties
     */
    @Override
    protected boolean extractReplicateAsynchronously(Properties properties) {
        boolean replicateAsynchronously;
        String replicateAsynchronouslyString = ITDPropertyPlaceholderConfigurer.getPropertiesMap().get(ITDApplicationConstants.REPLICATE_ASYNCHRONOUSLY);
        if (replicateAsynchronouslyString != null) {
            replicateAsynchronously = PropertyUtil.parseBoolean(replicateAsynchronouslyString);
        } else {
            replicateAsynchronously = true;
        }
        log.debug("Extracted replicateAsynchronously = " + replicateAsynchronously);
        return replicateAsynchronously;
    }

    /**
     * Extracts the value of replicateRemovals from the properties
     * @param properties
     */
    @Override
    protected boolean extractReplicateRemovals(Properties properties) {
        boolean replicateRemovals;
        String replicateRemovalsString = ITDPropertyPlaceholderConfigurer.getPropertiesMap().get(ITDApplicationConstants.REPLICATE_REMOVALS);
        if (replicateRemovalsString != null) {
            replicateRemovals = PropertyUtil.parseBoolean(replicateRemovalsString);
        } else {
            replicateRemovals = true;
        }
        log.debug("Extracted replicateRemovals = " + replicateRemovals);
        return replicateRemovals;
    }

    /**
     * Extracts the value of replicateUpdatesViaCopy from the properties
     * @param properties
     */
    @Override
    protected boolean extractReplicateUpdatesViaCopy(Properties properties) {
        boolean replicateUpdatesViaCopy;
        String replicateUpdatesViaCopyString = ITDPropertyPlaceholderConfigurer.getPropertiesMap().get(ITDApplicationConstants.REPLICATE_UPDATES_VIA_COPY);
        if (replicateUpdatesViaCopyString != null) {
            replicateUpdatesViaCopy = PropertyUtil.parseBoolean(replicateUpdatesViaCopyString);
        } else {
            replicateUpdatesViaCopy = true;
        }
        log.debug("Extracted replicateUpdatesViaCopy = " + replicateUpdatesViaCopy);
        return replicateUpdatesViaCopy;
    }

    /**
     * Extracts the value of replicatePutsViaCopy from the properties
     * @param properties
     */
    @Override
    protected boolean extractReplicatePutsViaCopy(Properties properties) {
        boolean replicatePutsViaCopy;
        String replicatePutsViaCopyString = ITDPropertyPlaceholderConfigurer.getPropertiesMap().get(ITDApplicationConstants.REPLICATE_PUTS_VIA_COPY);
        if (replicatePutsViaCopyString != null) {
            replicatePutsViaCopy = PropertyUtil.parseBoolean(replicatePutsViaCopyString);
        } else {
            replicatePutsViaCopy = true;
        }
        log.debug("Extracted replicatePutsViaCopy = " + replicatePutsViaCopy);
        return replicatePutsViaCopy;
    }

    /**
     * Extracts the value of replicateUpdates from the properties
     * @param properties
     */
    @Override
    protected boolean extractReplicateUpdates(Properties properties) {
        boolean replicateUpdates;
        String replicateUpdatesString = ITDPropertyPlaceholderConfigurer.getPropertiesMap().get(ITDApplicationConstants.REPLICATE_UPDATES);
        if (replicateUpdatesString != null) {
            replicateUpdates = PropertyUtil.parseBoolean(replicateUpdatesString);
        } else {
            replicateUpdates = true;
        }
        log.debug("Extracted replicateUpdates = " + replicateUpdates);
        return replicateUpdates;
    }

    /**
     * Extracts the value of replicatePuts from the properties
     * @param properties
     */
    @Override
    protected boolean extractReplicatePuts(Properties properties) {
        boolean replicatePuts;
        String replicatePutsString = ITDPropertyPlaceholderConfigurer.getPropertiesMap().get(ITDApplicationConstants.REPLICATE_PUTS);
        if (replicatePutsString != null) {
            replicatePuts = PropertyUtil.parseBoolean(replicatePutsString);
        } else {
            replicatePuts = true;
        }
        log.debug("Extracted replicatePuts = " + replicatePuts);
        return replicatePuts;
    }

}

所以这将解决您的第一个问题,即当出现非一致性缓存时,它会删除 运行 缓存中的所有条目。现在,进入第二个。

新启动的非一致性缓存不会与其他 运行 缓存自动同步

参考 this 答案,它告诉您如何自动执行此操作,否则您也可以通过一段代码手动执行此操作,以使用值加载新启动的非一致性缓存。

提示 如果您不知道如何手动操作 - 当您的应用程序启动时加载数据(从数据库或平面文件等)然后使用 cache.put 放入缓存。