我有一个相当简单的缓存配置:
<cache name="MyCache"
maxElementsInMemory="200000"
eternal="false"
timeToIdleSeconds="43200"
timeToLiveSeconds="43200"
overflowToDisk="false"
diskPersistent="false"
memoryStoreEvictionPolicy="LRU"
/>
我按以下方式创建缓存:
private Ehcache myCache =
CacheManager.getInstance().getEhcache("MyCache");
我像这样使用我的缓存:
public MyResponse processRequest(MyRequest request) {
Element element = myCache.get(request);
if (element != null) {
return (MyResponse)element.getValue();
} else {
MyResponse response = remoteService.process(request);
myCache.put(new Element(request, response));
return response;
}
}
每10,000次调用processRequest()方法,我就会记录关于我的缓存的统计信息:
logger.debug("Cache name: " + myCache.getName());
logger.debug("Max elements in memory: " + myCache.getMaxElementsInMemory());
logger.debug("Memory store size: " + myCache.getMemoryStoreSize());
logger.debug("Hit count: " + myCache.getHitCount());
logger.debug("Miss count: " + myCache.getMissCountNotFound());
logger.debug("Miss count (because expired): " + myCache.getMissCountExpired());
..我看到了大量的点击,这告诉我它正在工作。
..但是,我所看到的是,几个小时后,getMemoryStoreSize()开始超过getMaxElementsInMemory()。最终,它变得越来越大,并且使jvm变得不稳定,因为GC开始不间断地执行Full GCs以回收内存(并且我有一个相当大的上限集)。当我分析堆时,它指向LRU的SpoolingLinkedHashMap占用了大部分空间。
我确实有很多请求命中这个缓存,而我的理论是ehcache的LRU算法可能跟不上在它满了时驱逐元素。我尝试了LFU策略,它也导致内存存储器超过maxElements。
然后我开始查看ehcache代码,看看我是否可以证明我的理论(在LruMemoryStore $ SpoolingLinkedHashMap中):
private boolean removeLeastRecentlyUsedElement(Element element) throws CacheException {
//check for expiry and remove before going to the trouble of spooling it
if (element.isExpired()) {
notifyExpiry(element);
return true;
}
if (isFull()) {
evict(element);
return true;
} else {
return false;
}
}
..从这里看起来没问题,然后看了一下evict()方法:
protected final void evict(Element element) throws CacheException {
boolean spooled = false;
if (cache.isOverflowToDisk()) {
if (!element.isSerializable()) {
if (LOG.isDebugEnabled()) {
LOG.debug(new StringBuffer("Object with key ").append(element.getObjectKey())
.append(" is not Serializable and cannot be overflowed to disk"));
}
} else {
spoolToDisk(element);
spooled = true;
}
}
if (!spooled) {
cache.getCacheEventNotificationService().notifyElementEvicted(element, false);
}
}
..这看起来并没有真正驱逐(尽管有名字),而是依赖于打电话来驱逐。所以我查看了put()方法的实现,我没有看到它调用它。我在这里明显遗漏了一些东西,并希望得到一些帮助。
谢谢!
答案 0 :(得分:1)
您的配置对我来说还不错。只需使用右键即可进行缓存。
请勿将完整的请求对象用作缓存的键。从您的请求对象中放入一些唯一值。例如:
MyResponse response = remoteService.process(request);
myCache.put(new Element(request.getCustomerID(), response));
return response;
这应该为您工作。缓存不起作用的原因是每次请求对象都是新对象时;它永远不会从缓存中找到响应,因此会不断添加到缓存中。
答案 1 :(得分:0)
maxElementsInMemory
属性已过时,请改用maxEntriesLocalHeap