NHibernate Кэширование Дилемма - PullRequest
0 голосов
/ 01 марта 2010

Мое приложение включает в себя клиент, веб-уровень (балансировка нагрузки), уровень приложения (балансировка нагрузки) и уровень базы данных. Веб-уровень предоставляет услуги клиентам и перенаправляет вызовы на уровень приложения. Затем уровень приложения выполняет запросы к базе данных (используя 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 не подходит для моих нужд. Я хотел бы иметь возможность:

  1. Сконфигурируйте его так, чтобы в кэше всегда были данные за последние 7 дней. например. «Для этой таблицы кэшируйте все записи, где это поле находится между 7 днями назад и сейчас».
  2. Иметь возможность вручную поддерживать кеш. Когда новые данные поступают в систему, было бы хорошо, если бы я мог просто выбросить их прямо в кеш, а не ждать, пока кеш не станет недействительным. Точно так же, поскольку данные выпадают из периода времени, я хотел бы иметь возможность извлечь их из кэша.
  3. Имейте 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. Я уже подумал, что куб будет выполнять вычисления агрегации намного быстрее, но это все еще оставляет узкое место в базе данных. Я вполне могу использовать куб в дополнение к кешу, но отсутствие кеша - моя главная задача прямо сейчас.

Ответы [ 3 ]

2 голосов
/ 02 марта 2010

Прекратите использовать ваш транзакционный (OLTP) источник данных для аналитических (OLAP) запросов, и проблема исчезнет.

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

Повышение производительности должно быть значительным, поскольку вы можете оптимизировать сторону чтения для быстрого поиска по многим критериям, оптимизируя сторону записи для быстрого поиска по идентификатору и уменьшенной загрузке индекса при записи.

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

1 голос
/ 01 марта 2010

Определите 2 области кэша: «агрегация» и «агрегация. Сегодня» с большим сроком действия. Используйте их для запросов агрегации за предыдущие дни и сегодня соответственно.

В DoIt() выполните 1 запрос NH в день в запрошенном диапазоне, используя кешируемые запросы. Объедините результаты запроса в C #.

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

При изменении сегодняшних данных очистите область кэша «aggregation.today». Если вы хотите быстро перезагрузить эту область кэша, либо сделайте это немедленно, либо используйте другой более частый фоновый процесс, который вызывает DoIt() на сегодняшний день.

Если у вас включено кэширование запросов, NHibernate по возможности извлечет результаты из кэша. Это основано на запросе и значениях параметров.

0 голосов
/ 02 марта 2010

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

Вместо того, чтобы пытаться покрыть O / R Mapper вашими потребностями, я думаю, что более разумно использовать собственную стратегию управления данными / кешем.

Кроме того, правило 7-дневного кэширования, о котором вы говорите, звучит как что-то, связанное с бизнесом, ведь что-то, о чем картограф O / R не должен знать.

В заключение заставьте ваше приложение работать без какого-либо кэширования, чем использовать профилировщик (или более - .net, sql, nhibernate profiler), чтобы увидеть узкие места и начать улучшать «красные» части, в конечном итоге добавив кеширование любые другие оптимизации.

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

надеюсь, это поможет

...