Поддерживает ли какой-либо кэш данных asp.net фоновое заполнение записей в кэше? - PullRequest
9 голосов
/ 01 августа 2010

У нас есть управляемый данными веб-сайт ASP.NET, который был написан с использованием стандартного шаблона для кэширования данных (адаптированного здесь из MSDN):

public DataTable GetData()
{
   string key = "DataTable";
   object item = Cache[key] as DataTable;
   if((item == null)
   {
      item = GetDataFromSQL();
      Cache.Insert(key, item, null, DateTime.Now.AddSeconds(300), TimeSpan.Zero;
   }
   return (DataTable)item;
}

Проблема в том, что вызов GetDataFromSQL () дорого и использование сайта довольно высоко.Таким образом, каждые пять минут, когда кэш сбрасывается, сайт становится очень «зависающим», в то время как множество запросов ожидает получения новых данных.

То, что мы действительно хотим, это чтобы старые данныеостаются актуальными, пока новые данные периодически перезагружаются в фоновом режиме.(Тот факт, что кто-то может поэтому видеть данные, которым шесть минут, не является большой проблемой - данные не , которые чувствительны ко времени).Это то, что я могу написать сам, но было бы полезно узнать, поддерживают ли альтернативные механизмы кэширования (я знаю такие имена, как Velocity, memcache) такой сценарий.Или я упускаю какой-то очевидный трюк со стандартным кэшем данных ASP.NET?

Ответы [ 3 ]

8 голосов
/ 10 августа 2010

Вы должны иметь возможность использовать делегат CacheItemUpdateCallback, который является 6-м параметром, который является 4-й перегрузкой для Insert при использовании ASP.NET Cache:

Cache.Insert(key, value, dependancy, absoluteExpiration,
    slidingExpiration, onUpdateCallback);

Должно работать следующее:

Cache.Insert(key, item, null, DateTime.Now.AddSeconds(300),
    Cache.NoSlidingExpiration, itemUpdateCallback);

private void itemUpdateCallback(string key, CacheItemUpdateReason reason,
    out object value, out CacheDependency dependency, out DateTime expiriation,
    out TimeSpan slidingExpiration)
{
    // do your SQL call here and store it in 'value'
    expiriation = DateTime.Now.AddSeconds(300);
    value = FunctionToGetYourData();
}

С MSDN :

Когда срок действия объекта в кеше истекает, ASP.NET вызывает Метод CacheItemUpdateCallback с ключ для элемента кэша и причина, по которой вы можете обновить вещь. Остальные параметры этого метод вне параметров. Вы поставляете новый кэшированный элемент и необязательно значения срока действия и зависимости до использовать при обновлении кэшированного элемента.

Обратный вызов обновления не вызывается, если кэшированный элемент явно удален используя вызов Remove ().

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

Если метод обратного вызова выдает исключение ASP.NET подавляет исключение и удаляет кэшированные значение.

Я не проверял это, поэтому вам, возможно, придется немного повозиться с ним, но это должно дать вам базовое представление о том, чего вы пытаетесь достичь.

0 голосов
/ 07 августа 2010

Во-первых, поместите дату, которая вам действительно нужна, в обедненный класс (также известный как POCO) вместо этой таблицы данных.

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

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

Ох, и SqlCacheDependency печально известна своей ненадежностью и может заставить вашу систему взломать безумные обновления.

0 голосов
/ 04 августа 2010

Я вижу, что есть потенциальное решение для этого с использованием AppFabric (кеш, ранее известный как Velocity) в том смысле, что оно позволяет блокировать кеширование пункт, чтобы он мог быть обновлен. Пока элемент заблокирован, обычные (не блокирующие) запросы Get по-прежнему работают в обычном режиме и возвращают текущую копию элемента в кэше.

Такой способ также позволит вам выделить ваш метод GetDataFromSQL для другого процесса, скажем, службы Windows, который запускается каждые пять минут, что должно облегчить работу вашего «липкого» сайта.


Или ...

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

(Кстати, лучший совет для прояснения ваших намерений при помещении объектов в кэш - в кэше имеется постоянная NoSlidingExpirationNoAbsoluteExpiration), которая более читаема, чем ваш Timespan.Zero)

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