【问题标题】:What should i do so that i can bootstrap caches from cluster cache peer?我应该怎么做才能从集群缓存对等方引导缓存?
【发布时间】:2017-10-06 10:14:58
【问题描述】:

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

当一个对等点出现时,它将与其他缓存不一致。当引导程序完成时,它将是 部分连贯。 Bootstrap 从随机对等点获取密钥列表,然后批量加载 来自随机同行。如果引导失败,那么缓存将不会启动(现在不是这样)。但是,如果一个 发生分布式缓存操作,然后被引导程序覆盖 可能不一致。

下面是我的 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版 Tomcat 6.0.44

希望有人告诉我怎么做,在 ehcache.xml 中配置或实现 一些接口。我在这个问题上花了很多时间。请!!!帮助我!!!

ps:我是第一次在stackoverflow上提问,如果有什么需要请告诉我。

【问题讨论】:

    标签: java caching ehcache


    【解决方案1】:

    您基本上有 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 类如下。请注意,它有代码来加载属性然后使用它 - 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 答案,它会告诉您如何自动执行此操作,否则您也可以通过一段代码手动执行此操作,以使用值加载新启动的非连贯缓存。

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

    【讨论】:

    • 谢谢!!第二个解决方案很有用!实际上,你提到的第一个问题,ehcache 的默认值是通过复制 put&update 的,即使你没有设置,它也会像你说的那样工作。
    • 很高兴知道你现在很好。您是否确定 ehcache 通过复制放置/更新,因为您可以检查实现并且您可以看到这些布尔值 (protected boolean replicatePutsViaCopy;) 没有默认值,并且默认布尔值是 false,所以如果没有明确的代码将它们设置为 true,它将为 false - grepcode.com/file/repo1.maven.org/maven2/net.sf.ehcache/ehcache/…
    • 我认为我们犯了一个错误,因为我说的是 RMICacheReplicatorFactory 而不是 RMISynchronousCacheReplicator。当我们配置上面提到的那些属性时,RMICacheReplicatorFactory 将使用它来创建 RMISynchronousCacheReplicator,当某些属性未配置时,RMICacheReplicatorFactory 会将每个属性的值设置为 true。见grepcode.com/file/repo1.maven.org/maven2/net.sf.ehcache/ehcache/…
    猜你喜欢
    • 2019-12-13
    • 1970-01-01
    • 2015-03-12
    • 1970-01-01
    • 1970-01-01
    • 2020-08-27
    • 1970-01-01
    • 2016-11-10
    • 1970-01-01
    相关资源
    最近更新 更多