NHibernate - счетчики с параллелизмом и кэшированием второго уровня
Я новичок в NHibernate и испытываю трудности при настройке его для моего текущего сайта. Этот веб-сайт будет работать на нескольких веб-серверах с одним сервером базы данных, и поэтому у меня возникают некоторые проблемы с параллелизмом. На сайте будет зарегистрировано около 50000 пользователей или около того, и у каждого пользователя будет страница профиля. На этой странице другие пользователи могут "понравиться" другому пользователю, так же, как Facebook. Это проблема параллелизма.
Я думал об использовании кэша второго уровня, скорее всего, с использованием провайдера MemChached, поскольку у меня будет несколько веб-серверов. Каков наилучший способ реализовать функцию "Мне нравится" с помощью NHibernate? Я думал о трех вариантах:
- Используйте простой запрос Count(). Будет таблица "User_Likes", где каждая строка будет представлять подобное от одного пользователя другому. Чтобы отобразить количество лайков, я бы просто спросил количество лайков для пользователя, которое было бы переведено в базу данных как простое
SELECT COUNT(*) FROM USER_LIKES WHERE ID = x
или что-то. Однако я полагаю, что это приведет к значительному снижению производительности, так как каждый раз, когда пользователь посещает страницу профиля и, как и другой пользователь, количество лайков должно быть пересчитано, кэш второго уровня или нет. - Используйте дополнительный
NumberOfLikes
столбец в таблице User и увеличивайте / уменьшайте это значение, когда пользователь любит или не любит другого пользователя. Это, однако, дает мне проблемы с параллелизмом. Используя простой цикл for, я проверил его, привлекая пользователя 1000 раз на двух серверах, и результат в БД составил около 1100 лайков. Это разница 900. Реалистичный тест или нет, это, конечно, не вариант. Теперь я смотрел на оптимистическую и пессимистическую блокировку как на решение (не так ли?), Но мой текущий шаблон репозитория на данный момент не подходит для использования этого, я боюсь, поэтому, прежде чем я это исправлю, я хотел бы знать если это правильный путь. - Как 2, но используя собственный HQL и сам пишу оператор обновления, что-то вроде
UPDATE User SET NumberOfLikes = NumberOfLikes + 1 WHERE id = x
, Это не вызовет проблем с параллелизмом в базе данных, верно? Однако я не уверен, будет ли какое-либо несоответствие данных на моих нескольких серверах из-за кэширования второго уровня.
Так что... мне очень нужен совет. Есть ли другой вариант? Это похоже на обычную ситуацию, и, безусловно, NHibernate должен поддержать это в элегантной манере. Я новичок в NHIbernate, поэтому четкий и подробный ответ необходим и ценится:-) Спасибо!
2 ответа
Я подозреваю, что вы увидите эту проблему в других местах. Вы можете решить эту конкретную проблему с помощью 3., но это оставляет другие места, где вы столкнетесь с проблемами параллелизма.
Я бы посоветовал реализовать пессимистическую блокировку. Обычный способ сделать это - просто применить транзакцию ко всему HTTP-запросу. С BeginRequest
в вашем Global.asax
, вы начинаете сеанс и транзакцию. Затем в EndRequest
Вы делаете это. С Error
В этом случае вы идете по альтернативному пути: откат и отмена сеанса.
Это вполне приемлемый способ применения NHibernate. Смотрите, например, http://dotnetslackers.com/articles/aspnet/Configuring-NHibernate-with-ASP-NET.aspx.
Я бы пошел с 3. Я считаю, что в такого рода приложениях это не так критично, если некоторые страницы какое-то время показывают немного устаревшее значение.
IIRC, обновления HQL не делают запись кэша сущностей недействительной, поэтому вам, возможно, придется сделать это вручную.