EhCache永恒的行为不如预期

时间:2016-04-21 04:49:04

标签: caching ehcache

我的要求是拥有基于磁盘的缓存。如果缓存是内存已满,我想将LRU元素推送到磁盘。然后如果磁盘上的文件已满,那么我希望磁盘上的LRU元素被驱逐。这是非常简单的要求,但是我无法使用EhCache实现这一点。

我使用了以下配置的EhCache(2.10.1):

 <defaultCache name="default"
       maxBytesLocalHeap="50m"
       maxBytesLocalDisk="100g"
       eternal="true"
       timeToIdleSeconds="0"        
       timeToLiveSeconds="0"
       diskExpiryThreadIntervalSeconds="120"
       memoryStoreEvictionPolicy="LRU">
       <persistence strategy="localTempSwap"/>
 </defaultCache>

我的期望是,当缓存填满时(即缓存大小超过50M),我希望将LRU元素推送到文件,从而为内存中的新元素创建一些空间。

然而,这不是EhCache的工作方式,我做了一个示例测试来检查缓存中的元素数量:

public static void main(String [] args)抛出异常{

ArrayList<String> keys = new ArrayList<String>();
CacheManager cacheManager;
FileInputStream fis = null;
try {
    fis = new FileInputStream(
            new File("src/config/ehcache.xml").getAbsolutePath());
    cacheManager = CacheManager.newInstance(fis);
}
finally {
    fis.close();
}

  java.lang.Runtime.getRuntime().addShutdownHook(new Thread(){
      @Override
    public void run() {

          try
          {
              System.out.println("Shutting down Eh Cache manager !!");
                 cacheManager.clearAll();
                 cacheManager.shutdown();
                 System.out.println("done !!");

          }catch(Exception e)
          {
              e.printStackTrace();
          }
                      }
  });

System.out.println("starting ...");
System.out.println(System.getProperty("java.io.tmpdir"));

cacheManager.addCache("work_item_111");

Cache ehCache = cacheManager.getCache("work_item_111");

long start_outer = System.currentTimeMillis();
for(int i =0;i<30;i++)
{
    long start = System.currentTimeMillis();
    String key = UUID.randomUUID().toString();
    ehCache.put(new Element(key, getNextRandomString()));
    keys.add(key);
    //System.out.println("time taken : " + (System.currentTimeMillis()- start));
    System.out.println((System.currentTimeMillis()- start) +" - " + (ehCache.getStatistics().getLocalDiskSizeInBytes()/1024/1024) + " - " +(ehCache.getStatistics().getLocalHeapSizeInBytes()/1024/1024));
}
System.out.println("time taken-total : " + (System.currentTimeMillis()- start_outer));
System.out.println(ehCache.getSize());

System.out.println("disk size : " +ehCache.getStatistics().getLocalDiskSizeInBytes()/1024/1024);
System.out.println("memory size : " +ehCache.getStatistics().getLocalHeapSizeInBytes()/1024/1024);

    Iterator<String> itr = keys.iterator();
    int count =0;
    while(itr.hasNext())
    {
        count++;
        String key = itr.next();
        if(ehCache.get(key) == null)
        {
            System.out.println("missingg key : " + key);
        }
    }
    System.out.println("checked for count :" + count);

}

结果非常令人失望,在缓存中放入30个元素(每个元素大小合适.4mb)后,我只能看到缓存中的7个元素(ehCache.getSize()返回7)并且我也看不到文件磁盘增长。

如果我在这里遗漏任何东西,任何EhCache专家都可以帮助我。感谢。

2 个答案:

答案 0 :(得分:1)

首先,关于Ehcache拓扑:

  • Ehcache背后的分层模型强制执行至少2.6,所有映射都存在于最低层,即您的情况下的磁盘中。

这意味着它不再是溢出模型。

现在,为什么你的测试表现与你期望的不同:

  • Ehcache 2.x磁盘层将密钥留在内存中,当堆的内存大小时,密钥占用的空间量将从该容量中减去。
  • Ehcache 2.x异步写入磁盘并且具有有限的队列。虽然在大多数用例中这不是问题,但在测试中如此紧凑的循环中,您可能会达到这些限制并通过逐行内联来降低缓存。

因此,为了更好地了解正在发生的事情,请查看调试中的Ehcache日志,看看究竟发生了什么。 如果您看到驱逐,只需循环更慢或增加磁盘写入队列的某些设置,例如缓存元素上的diskSpoolBufferSizeMB属性。

答案 1 :(得分:0)

面临同样的问题。在循环中,我添加了10k元素和缓存配置

 cacheConfiguration.maxBytesLocalHeap(1, MemoryUnit.MEGABYTES);
        cacheConfiguration.diskSpoolBufferSizeMB(10);
//        cacheConfiguration.maxEntriesLocalHeap(1);
        cacheConfiguration.name("smallcache");
        config.addCache(cacheConfiguration);
        cacheConfiguration.setDiskPersistent(true);
        cacheConfiguration.overflowToDisk(true);
        cacheConfiguration.eternal(true);

当将maxBytesLocalHeap增加到10时,没问题,当使用maxEntriesLocalHeap而不是maxBytes并且它甚至设置为值1(项目)时,它可以正常工作。

2.6版

这是答案Ehcache set to eternal but forgets elements anyway?