Проблема с использованием HttpRuntime.Cache - PullRequest
4 голосов
/ 23 июня 2009

Использую следующий код .net для добавления объектов в кеш:

public static void Add<T>(string key, T dataToCache)
{
    try
    {
        ApplicationLog.Instance.WriteInfoFormat("Inserting item with key {0} into Cache...", key);

        HttpRuntime.Cache.Insert(
            key,
            dataToCache,
            null,
            DateTime.Now.AddDays(7),
            System.Web.Caching.Cache.NoSlidingExpiration);
    }

    catch (Exception ex)
    {
        ApplicationLog.Instance.WriteException(ex);             
    }
}

и вот мой код для извлечения значений из кеша:

public static T Get<T>(string key) 
{   
    try
    {                
        if (Exists(key))
        {
            ApplicationLog.Instance.WriteInfoFormat("Retrieving item with key {0} from Cache...", key);

            return (T)HttpRuntime.Cache[key];
        }
        else
        {
            ApplicationLog.Instance.WriteInfoFormat("Item with key {0} does not exist in Cache.", key);
            return default(T); 
        }
    }
    catch(Exception ex)
    {
        ApplicationLog.Instance.WriteException(ex);
        return default(T); 
    }
}


public static bool Exists(string key)
{
    bool retVal = false;
    try
    {
        retVal= HttpRuntime.Cache[key] != null;
    }
    catch (Exception ex)
    {
        ApplicationLog.Instance.WriteException(ex);
    }
    return retVal; 
}

Но я обнаружил, что примерно каждые 2 минуты значение кэшируемого объекта устанавливается равным нулю, что приводит к повторному извлечению этого значения из базы данных.

Что мне здесь не хватает?

Ответы [ 3 ]

7 голосов
/ 08 июля 2009

Ну, во-первых, ваш доступ не синхронизирован, так что это большой источник проблем. Чтение из HttpRuntime Cache гарантированно является потокобезопасным, поэтому вам действительно следует попробовать прочитать свой элемент в качестве первого шага в каждой операции кэша.

Между проверкой, если Exists и фактическим извлечением предмета, может произойти много вещей (например, вашего предмета там больше нет). Вы должны получить дескриптор элемента, который вы ищете, и, если его там нет, предоставьте поточно-ориентированную вставку, извлекая его из постоянного хранилища данных.

Таким образом, ваша логика Add попадет внутрь вашего Get ЕСЛИ данных там нет. Нет ничего принципиально неправильного в предоставлении отдельной логики Add, и вы должны измерить стоимость многократного попадания в базу данных по сравнению с блокировкой дальнейших запросов для этого конкретного фрагмента данных.

T GetT(string key)
{
    T item = (cache.Get(key) as T);
    if (item == null)
    {
        lock (yourSyncRoot)
        {
            // double check it here
            item = (cache.Get(key) as T);
            if (item != null)
                return item;

            item = GetMyItemFromMyPersistentStore(key); // db?
            if (item == null)
                return null;

            string[] dependencyKeys = {your, dependency, keys};

            cache.Insert(key, item, new CacheDependency(null, dependencyKeys), 
                         absoluteExpiration, slidingExpiration, priority, null);
        }
    }
    return item;
}

В зависимости от вашей политики истечения срока действия вы получите свои данные в памяти и обеспечите быстрый и синхронизированный доступ к ним, но, как я уже сказал, измерьте их и настройте в соответствии с вашими потребностями. В вашей бизнес-логике после обновления вашего предмета и правильного сохранения его в постоянном хранилище, просто удалите его из кэша, и следующий вызов вашего Get получит его снова.

6 голосов
/ 23 июня 2009

Когда вы каждые две минуты говорите, что введенное значение равно нулю, означает ли это только интересующий вас элемент или каждый элемент в кэше?

Я спрашиваю это, потому что кеш существует только до тех пор, пока приложение работает. Если приложение перезапускается, кэш уходит. Это объясняет поведение, если все уходит каждые 2 минуты. В этом случае у вас на руках другая проблема: почему приложение перезапускается каждые 2 минуты.

Если это только НЕКОТОРЫЕ элементы, то это может быть проблема с памятью. Кэш очищается в ответ на нехватку памяти. Я считаю, что есть способ установить приоритет для вставленных значений. Но это должно быть проблемой только тогда, когда у вас мало памяти.

Если это все еще не решит вашу проблему, есть способ узнать, почему элемент удаляется. Это объясняется здесь .

2 голосов
/ 23 июня 2009

Это может быть из-за нехватки памяти, кеш автоматически уничтожает элементы в кеше, когда памяти становится мало. Существует необязательный параметр для установки приоритета элементов в кеше, если вы хотите очистить один элемент перед другим.

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