У меня возникают проблемы с тем, что мой кеш работает так, как я хочу.
Проблема: Процесс извлечения запрошенных данных занимает много времени. Если вы используете стандартное кэширование ASP.NET, некоторые пользователи получат "хит" для извлечения данных. Это неприемлемо.
Решение?: Не очень важно, чтобы данные были на 100% текущими. Я хотел бы обслуживать старые недействительные данные при обновлении кэшированных данных в другом потоке, чтобы новые данные были доступны для будущих запросов. Я считаю, что данные необходимо каким-то образом сохранить, чтобы иметь возможность обслуживать первого пользователя после перезапуска приложения без того, чтобы пользователь "ударил".
Я сделал решение, которое делает что-то вроде выше, но мне интересно, есть ли способ "наилучшей практики" или существует каркас кэширования, который уже поддерживает это поведение?
Я создал собственное решение с помощью словаря /Hashtable в памяти как дубликат фактического кеша. Когда вызов метода приходил в запрос объекта из кеша, и он не был там, но присутствовал в памяти, возвращаемый объект памяти возвращался и запускал новый поток для обновления объекта как в памяти, так и в кеше с использованием метода делегата.
Есть инструменты, которые делают это, например, Microsoft ISA Server (может быть немного дороже /overkill ).
Вы можете кэшировать его в памяти с помощью Enterprise Libary Caching. Пусть ваши пользователи читают Cache и имеют другие страницы, которые обновляют Cache, эти другие страницы следует вызывать как можно чаще, так как вам нужно сохранить данные до даты.
Вы можете сделать это довольно легко с классами Cache
и Timer
, встроенными в .NET. Таймер запускается в отдельном потоке.
И я на самом деле написал очень маленькую библиотеку-оболочку под названием WebCacheHelper, которая раскрывает эту функциональность в перегруженном конструкторе. Библиотека также служит строго типизированной оболочкой вокруг объекта Cache
.
Вот пример того, как вы могли это сделать...
public readonly static WebCacheHelper.Cache<int> RegisteredUsersCount =
new WebCacheHelper.Cache<int>(new TimeSpan(0, 5, 0), () => GetRegisteredUsersCount());
У этого есть ленивый аспект загрузки, где GetRegisteredUsersCount()
будет выполняться в вызывающем потоке в тот момент, когда RegisteredUsersCount
получает первый доступ. Однако после этого он выполняется каждые 5 минут в фоновом потоке. Это означает, что единственным пользователем, который будет наказан с медленным временем ожидания, будет самый первый пользователь.
Затем получение значения так же просто, как ссылка RegisteredUsersCount.Value
.
Вы можете слушать, когда Cached Item будет удален и обработать,
public void RemovedCallback(String k, Object v, CacheItemRemovedReason r)
{
// Put Item Back IN Cache, ( so others can use it until u have finished grabbing the new data)
// Spawn Thread to Go Get Up To Date Data
// Over right Old data with new return...
}
в глобальном asax
protected void Application_Start(object sender, EventArgs e)
{
// Spawn worker thread to pre-load critical data
}
Ох... Я понятия не имею, если это лучшая практика, я просто подумал, что это будет пятно ~ Удачи ~
В этой ситуации я использую CacheTable в db для кэширования последних данных и запуска фонового задания (с помощью службы Windows. в общей среде вы также можете использовать потоки), которая обновляет данные в таблице.
Существует очень мало шансов показать пользователю пустой экран. Я исключаю это путем кэширования через кеш asp.net в течение 1 минуты.
Не знаю, плохой дизайн, но он отлично работает без проблем на высокоиспользуемом веб-сайте.
Да, вы можете просто кэшировать наиболее часто используемые данные, когда ваше приложение запускается, но это все равно означает, что первый пользователь должен запускать, что "возьмет удар", как вы говорите (предполагается, что в кэше propro конечно).