共有三台服务器,均部署了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 tomcat 6.0.44
希望有人告诉我该怎么做,在ehcache.xml中配置或实现 一些接口(interface)。我在这个问题上花了很多时间。请帮助我!!!
ps:我是第一次在stackoverflow上提问,如果有什么需要请告诉我。
最佳答案
您基本上有两个问题 - 首先,当非一致性缓存启动时,其他正在运行的缓存会变空,第二新启动的非一致性缓存不会自动与其他正在运行的缓存同步。让我尝试一一解决。
当非一致性缓存启动时,其他正在运行的缓存会变空
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
类如下所示。请注意,它具有加载属性然后使用它的代码 - StringreplicatePutsString = 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
将其放入缓存中。
关于java - 我应该怎么做才能从集群缓存对等方引导缓存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43847155/