ehcache не соблюдает maxElementsInMemory - PullRequest
2 голосов
/ 21 декабря 2011

У меня довольно простая конфигурация кеша:

 <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;
    }
}


Каждые 10000 вызовов метода 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 GC без остановок, чтобы восстановить память (и у меня довольно большой набор ограничений). Когда я профилировал кучу, он указал на SpoolingLinkedHashMap LRU, занимающий большую часть пространства.

У меня действительно много запросов, попадающих в этот кеш, и моя теория состоит в том, что алгоритм LRU в ehcache, возможно, не поспевает за удалением элементов, когда он заполнен. Я попробовал политику 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 () и не вижу его вызывающего. Я явно что-то здесь упускаю и буду признателен за помощь.

Спасибо!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...