Мое приложение включает в себя клиент, веб-уровень (балансировка нагрузки), уровень приложения (балансировка нагрузки) и уровень базы данных. Веб-уровень предоставляет услуги клиентам и перенаправляет вызовы на уровень приложения. Затем уровень приложения выполняет запросы к базе данных (используя NHibernate) и возвращает результаты.
Данные в основном читаются, но записи происходят довольно часто, особенно когда новые данные поступают в систему. Гораздо чаще данные агрегируются, и эти агрегации возвращаются клиенту, а не исходным данным.
Как правило, пользователи будут интересоваться агрегацией последних данных - скажем, с прошлой недели. Таким образом, для меня имеет смысл ввести кеш, включающий все данные за последние 7 дней. Я не могу просто кэшировать сущности, когда и когда они загружены, потому что мне нужно агрегировать по диапазону сущностей, и этот диапазон диктуется клиентом наряду с другими сложностями, такими как фильтры. Мне нужно знать, все ли данные в этом диапазоне находятся в кэше или нет.
В моем идеальном фэнтезийном мире мои услуги вообще не должны были бы меняться:
public AggregationResults DoIt(DateTime starting, DateTime ending, Filter filter)
{
// execute HQL/criteria call and have it automatically use the cache where possible
}
Будет отдельный фильтрующий слой, который будет подключаться к NHibernate и будет разумно и прозрачно определять, может ли HQL / критерий запроса выполняться к кешу или нет, и будет обращаться к базе данных только при необходимости. Если бы все данные находились в кеше, он запросил бы сами кешированные данные, что-то вроде базы данных в памяти.
Однако при первом осмотре механизм кэширования второго уровня NHibernate не подходит для моих нужд. Я хотел бы иметь возможность:
- Сконфигурируйте его так, чтобы в кэше всегда были данные за последние 7 дней. например. «Для этой таблицы кэшируйте все записи, где это поле находится между 7 днями назад и сейчас».
- Иметь возможность вручную поддерживать кеш. Когда новые данные поступают в систему, было бы хорошо, если бы я мог просто выбросить их прямо в кеш, а не ждать, пока кеш не станет недействительным. Точно так же, поскольку данные выпадают из периода времени, я хотел бы иметь возможность извлечь их из кэша.
- Имейте NHibernate разумно понять, когда он может обслуживать запрос непосредственно из кэша, а не попадать в базу данных вообще. например. Если пользователь запрашивает агрегирование данных за последние 3 дня, эта агрегация должна рассчитываться непосредственно из кэша, а не касаться БД.
Теперь, я почти уверен, что # 3 просит слишком много. Даже если я смогу заполнить кэш всеми необходимыми данными, NHibernate не знает, как эффективно запросить эти данные. В буквальном смысле пришлось бы перебирать все сущности, чтобы различать, которые имеют отношение к запросу (честно говоря, это может быть хорошо). Кроме того, это потребовало бы реализации механизма запросов NHibernate, который выполнялся против объектов, а не базы данных. Но я могу мечтать, верно?
Предполагая, что # 3 требует слишком много, мне потребуется некоторая логика в моих службах, например:
public AggregationResults DoIt(DateTime starting, DateTime ending, Filter filter)
{
if (CanBeServicedFromCache(starting, ending, filter))
{
// execute some LINQ to object code or whatever to determine the aggregation results
}
else
{
// execute HQL/criteria call to determine the aggregation results
}
}
Это не идеально, потому что каждый сервис должен учитывать кэш и должен дублировать логику агрегации: один раз для запросов к базе данных через NHibernate и один раз для запросов в кэш.
При этом было бы неплохо, если бы я мог хотя бы сохранить соответствующие данные в кэше второго уровня NHibernate. Это позволило бы другим службам (которые не выполняют агрегацию) получать прозрачную выгоду от кэша. Это также гарантировало бы, что я не удваиваю кэшированные объекты (один раз в кэше второго уровня и один раз в моем собственном отдельном кэше), если когда-нибудь решу, что кэш второго уровня требуется в другом месте системы.
Я подозреваю, что если я смогу овладеть реализацией ICache
во время выполнения, все, что мне нужно сделать, это вызвать метод Put()
, чтобы вставить мои данные в кеш. Но это может быть наступление на опасную землю ...
Может ли кто-нибудь рассказать о том, может ли какое-либо из моих требований быть выполнено механизмом кэширования второго уровня NHibernate? Или я должен просто свернуть свое собственное решение и вообще отказаться от кэша второго уровня NHibernate?
Спасибо
PS. Я уже подумал, что куб будет выполнять вычисления агрегации намного быстрее, но это все еще оставляет узкое место в базе данных. Я вполне могу использовать куб в дополнение к кешу, но отсутствие кеша - моя главная задача прямо сейчас.