Допустим, я не испольюу длинных сессий, ограничивая время жизни сессии одним HTTP-запросом. Также не использую detached-объекты, то есть время жизни объектов в памяти ограничено одним HTTP-запросом. В итоге я как бы получаю идеологически чистый stateless.
Кеш первого уровня живёт столько же. В случае многошаговых диалогов, серверный обработчик каждого шага явным образом лезет в базу (или в кеш второго уровня, ежели он имеется... вопросы ниже) для проверки корректности данного шага и, возможно, всех предыдущих шагов внутри сценария.
Вопрос 1: Пока что всё правильно?
Далее про кеши, живущие дольше одного HTTP-запроса (Hibernate's 2nd level cache). IT говорил
, что в stateless-модели в кластере отсутствует необходимость синхронизации кешей нодов, достаточно броадкастить команду сброса кеша. Это решает проблему горизонтального трафика между нодами и, как следствие, масштабируемости. Вопросы следующие:
Вопрос 2: Не слишком ли это круто — сбрасывать весь кеш? На других машинах могут обрабатываться и кешироваться не связанные данные. Как это решается (идеологически, без привязки конкретно к Hibernate)? Лично мне в голову приходит только обмен короткими сообщениями вида "users.12", что означает "сбрось нафиг все данные, имеющие хоть какое-то отношение к пользователю ID=12".
Вопрос 3: Поддерживаются ли эти решения в JBoss Cache (или как там его зовут... кластерный кеш, который может быть задействован в качестве Hibernate 2nd level cache)? Спрашиваю, потому что боюсь лезть в доки, чтобы не случилось memory overflow от изобилия деталей при отсутствии общего понимания.
Вопрос 4: Даже если JBoss Cache обеспечивает вышеупомянутую поддержку для stateless-приложений, то Hibernate 2nd level cache, насколько я понял, всё равно не поддерживает этой радости, т.е. гоняет сериализованные объекты между нодами. Это так? Если да, то как дальше жить?
Возможно, я просто паникёрствую. Авторы книжки утверждают, что при правильной архитектуре всё должно замечательно работать без всяких 2nd level cache. Если кидать в кластерный кеш только редко изменяющиеся данные, то их при случае и сбросить не жалко. Но тем не менее, гложет меня сомнение, что я чего-то недопонимаю... точнее, недо-знаю.
Здравствуйте, Дм.Григорьев, Вы писали:
ДГ>Вопрос 0: А пригоден ли Hibernate вообще для написания действительно масштабируемых систем
Делаю проект без Hibernate, т.к. стандартными средствами в _моем случае_ сделать намного легче, чем городить что-то с hibernate. Проект довольно большой.
Re[2]: Stateless-сервер на Hibernate: кеширование и вообще
Здравствуйте, Gangsta, Вы писали:
ДГ>>Вопрос 0: А пригоден ли Hibernate вообще для написания действительно масштабируемых систем
G>Делаю проект без Hibernate, т.к. стандартными средствами в _моем случае_ сделать намного легче, чем городить что-то с hibernate. Проект довольно большой.
(1) "Большой" понятие растяжимое.
(2) То, что можно без Hibernate, это и так ясно. А вот можно ли с Hibernate? У меня почему-то устойчивое подозрение, что нельзя. Объектная модель будет пихать палки в колёса даже в мелочах: например, чтобы добавить элемент в коллекцию, нужно будет эту коллекцию вначале прочитать (в итоге select + insert вместо голого insert).
, что в stateless-модели в кластере отсутствует необходимость синхронизации кешей нодов, достаточно броадкастить команду сброса кеша. Это решает проблему горизонтального трафика между нодами и, как следствие, масштабируемости. Вопросы следующие:
ДГ>Вопрос 2: Не слишком ли это круто — сбрасывать весь кеш? На других машинах могут обрабатываться и кешироваться не связанные данные. Как это решается (идеологически, без привязки конкретно к Hibernate)? Лично мне в голову приходит только обмен короткими сообщениями вида "users.12", что означает "сбрось нафиг все данные, имеющие хоть какое-то отношение к пользователю ID=12".
Кеширование относится к классу задач, решения для которых находятся в диапазоне от просто глобальной переменной, до сложнейших распределённых систем, которые по сложности и стоимости могут многократно превосходить программы, которые их используют. Соответственно, ответ на твой вопрос зависит от того сколько сил, времени и/или денег ты готов на это потратить. И будут ли сопоставимы эти затраты с полученным результатом.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re: Stateless-сервер на Hibernate: кеширование и вообще
Здравствуйте, Дм.Григорьев, Вы писали:
ДГ>Вопрос 0: А пригоден ли Hibernate вообще для написания действительно масштабируемых систем (таких, как mamba.ru, крутящаяся на 200 серверах
)?
Да. Blogger.com так работает, например. У нас тоже не 200 серверов, но вполне себе кластер — тоже никаких проблем.
ДГ>Допустим, я не испольюу длинных сессий, ограничивая время жизни сессии одним HTTP-запросом. Также не использую detached-объекты, то есть время жизни объектов в памяти ограничено одним HTTP-запросом. В итоге я как бы получаю идеологически чистый stateless. ДГ>Кеш первого уровня живёт столько же. В случае многошаговых диалогов, серверный обработчик каждого шага явным образом лезет в базу (или в кеш второго уровня, ежели он имеется... вопросы ниже) для проверки корректности данного шага и, возможно, всех предыдущих шагов внутри сценария. ДГ>Вопрос 1: Пока что всё правильно?
Да. В данном случае у тебя workflow с Hibernate ничем не отличается от обычного использования SQL. Просто Hibernate тебе дает красивый объектный интерфейс.
ДГ>Далее про кеши, живущие дольше одного HTTP-запроса (Hibernate's 2nd level cache). IT говорил
, что в stateless-модели в кластере отсутствует необходимость синхронизации кешей нодов, достаточно броадкастить команду сброса кеша. Это решает проблему горизонтального трафика между нодами и, как следствие, масштабируемости. Вопросы следующие:
Да, примерно. Но тут могут быть проблемы с транзакционностью, так что простым броадкастом не отделаться, если integrity данных очень важна.
ДГ>Вопрос 4: Даже если JBoss Cache обеспечивает вышеупомянутую поддержку для stateless-приложений, то Hibernate 2nd level cache, насколько я понял, всё равно не поддерживает этой радости, т.е. гоняет сериализованные объекты между нодами. Это так? Если да, то как дальше жить?
В общем, провожу краткий ликбез по 2-nd level cache.
Stateless-ность приложения не имеет НИКАКОГО отношения к кэшу второго уровня. Этот кэш живет между запросами и используется только для ускорения работы Hibernate, он не хранит никакого состояния уровня приложения.
Теперь про его кластеризацию — тебе нужно в общем случае (в частных случаях может быть достаточно readonly caches, например, для словарей) обеспечивать когерентность кэшей между нодами. Тут у тебя есть два метода — кластерная инвалидация (при модификации объекта он сбрасывается из кэшей со всех нод) и кластерная репликация.
Как ни странно, репликация эффективнее инвалидации при определенных условиях — так как в случае инвалидации нодам придется загружать сброшеные объекты из БД.
Hibernate поддерживает обе стратегии, причем автоматически (что очень приятно). То есть, у тебя будут реплицироваться/инвалидироваться ТОЛЬКО измененные объекты (кстати, замечательно живет в симбиозе с автоматическим версированием объектов, тоже поддерживаемым Hibernate).
Теперь про конкретные реализации для кэширования (поддерживающие Hibernate): Oracle Coherence (бывший Tangosol Coherence) — http://www.oracle.com/technology/products/coherence/index.html . Абсолютно super-duper-cool решение для кластерных кэшей, там поддерживается репликация+инвалидация с автоматической баллансировкой кэшей (говорят, что масштабируется до тысяч узлов). В success stories у них есть пример банка, который работал несколько часов чисто из кэша после отказа базы данных. Один минус — стоит денег.
JBoss Cache — поддерживает репликацию и инвалидацию. Но в некоторых случаях глючный, и медленный. Честно говоря, мне не очень понравился, хотя у нас работает нормально после допинывания. По фичам лучший среди OpenSource.
EhCache (http://ehcache.sourceforge.net/) — поддерживает кластерную репликацию и инвалидацию, быстрый. НО не транзакционный, так что его небезопасно использовать (обещают вскоре исправить) в кластере при определенных условиях.
OsCache (http://www.opensymphony.com/oscache/) — поддерживает только инвалидацию, быстрый, маленький. Тоже нетранзакционный.
EhCache+Terracotta (http://www.terracotta.org/) — используется EhCache в локальном режиме и кластеризуется с помощью Terracotta. При этом мы получаем поддержку транзакционности — Terracotta вообще позволяет абсолютно прозрачно кластеризовать многие приложения.
Да, все эти решения почти никак не влияют на само приложение — можно при желании без проблем менять одно на другое.
Теперь еще несколько наблюдений — большая часть этих решений поддерживает disk overflow cache. То есть, можно использовать локальные диски на узлах для дополнительного хранилища. В некоторых случаях это очень полезно, например, если узлы в нормальном состоянии почти не используют локальные диски.
Хорошо продуманое кэширование часто позволяет снизить нагрузку на базу данных в десятки раз, так что оно того стоит. Еще одно замечение, Hibernate не поддерживает кэширование для определенных мэпингов (использующих SQL-формулы, хранимые процедуры для взятия коллекций и т.п.) — так что тут надо внимательнее.
PS: давно хочу статью написать про кэширование
Sapienti sat!
Re[3]: Stateless-сервер на Hibernate: кеширование и вообще
ДГ>(2) То, что можно без Hibernate, это и так ясно. А вот можно ли с Hibernate? У меня почему-то устойчивое подозрение, что нельзя. Объектная модель будет пихать палки в колёса даже в мелочах: например, чтобы добавить элемент в коллекцию, нужно будет эту коллекцию вначале прочитать (в итоге select + insert вместо голого insert).
Там, где тебе важен каждый roundtrip любой ORM не подойдет и надо ручками все оптимизировать и вылизывать каждый план выполнения.
Но обычно такого кода немного, зато очень много типового кода, который чем проще писать, тем лучше и пусть хоть как-нибудь выполняется. И вот тут ЩКЬ может помочь снизить трудоемкость разработки.
Re[4]: Stateless-сервер на Hibernate: кеширование и вообще
Здравствуйте, Igor Trofimov, Вы писали:
ДГ>>(2) То, что можно без Hibernate, это и так ясно. А вот можно ли с Hibernate? У меня почему-то устойчивое подозрение, что нельзя. Объектная модель будет пихать палки в колёса даже в мелочах: например, чтобы добавить элемент в коллекцию, нужно будет эту коллекцию вначале прочитать (в итоге select + insert вместо голого insert). iT>Там, где тебе важен каждый roundtrip любой ORM не подойдет и надо ручками все оптимизировать и вылизывать каждый план выполнения. iT>Но обычно такого кода немного, зато очень много типового кода, который чем проще писать, тем лучше и пусть хоть как-нибудь выполняется. И вот тут ЩКЬ может помочь снизить трудоемкость разработки.
Популярное заблуждение. Тот же Hibernate можно использовать как тупой маппер с результатов SQL-запросов с ничтожным оверхедом.
А кэш второго уровня в Hibernate часто позволяет за счет кэширования получить скорость доступа в десятки раз быстрее SQL-запрсов (взятие объекта или коллекции из локального кэша в Hibernate примерно в тысячу раз быстре SQL-запроса).
Sapienti sat!
Re[2]: Stateless-сервер на Hibernate: кеширование и вообще
Спасибо огромное.
ДГ>>...в кластере отсутствует необходимость синхронизации кешей нодов, достаточно броадкастить команду сброса кеша. Это решает проблему горизонтального трафика между нодами и, как следствие, масштабируемости. C>Да, примерно. Но тут могут быть проблемы с транзакционностью, так что простым броадкастом не отделаться, если integrity данных очень важна.
Где можно прочитать подробнее про эти проблемы?
C>Stateless-ность приложения не имеет НИКАКОГО отношения к кэшу второго уровня. Этот кэш живет между запросами и используется только для ускорения работы Hibernate, он не хранит никакого состояния уровня приложения.
C>Еще одно замечение, Hibernate не поддерживает кэширование для определенных мэпингов (использующих SQL-формулы, хранимые процедуры для взятия коллекций и т.п.) — так что тут надо внимательнее.
В книжке "JP with Hibernate" таких деталей не нашёл. Где они описаны? Интересует и настройка стратегии сброс/репликация (доки по конкретному кешу, так?), и какие данные Hibernate гоняет между нодами (доки по Hibernate?).
C>PS: давно хочу статью написать про кэширование
Здравствуйте, IT, Вы писали:
IT>от просто глобальной переменной
Глобальной переменной, говоришь?...
Это идея! Бегемот, делай! Эйн, цвей, дрей!
В ближайшем обозримом будущем я вообще не собираюсь писать собственную реализацию кеша — наверняка всё уже давно написано. Проблема в том, что сориентироваться в огромном количестве доков по j2ee за конечное время нереально. Я потратил месяц на изучение Hibernate, и у меня остался ещё месяц (это типа отпуск за свой счёт), чтобы не накосячить лишнего при грядущей разработке очередного dating-портала.
Здравствуйте, Дм.Григорьев, Вы писали:
ДГ>Спасибо огромное.
Пожалуйста
ДГ>>>...в кластере отсутствует необходимость синхронизации кешей нодов, достаточно броадкастить команду сброса кеша. Это решает проблему горизонтального трафика между нодами и, как следствие, масштабируемости. C>>Да, примерно. Но тут могут быть проблемы с транзакционностью, так что простым броадкастом не отделаться, если integrity данных очень важна. ДГ>Где можно прочитать подробнее про эти проблемы?
Честно, не знаю Я еще не видел в Сети нормального описания работы с кэшированием.
Конкретно чем опасна нетранзакционная инвалидация:
1) Узел A делает непосредственно перед коммитом посылает инвалидацию.
2) Узел B получает сообщение об инвалидации, purge'ит объект из кэша.
3) На узел B поступает запрос, требующий только что за-purge'еный объект.
4) Узел B загружает этот объект из базы данных и кладет его в локальный кэш. Но в этот момент узел A еще не начал коммит в базу данных.
5) Узел A коммитит объект, но на узле B осталась его старая копия.
В ситуации с нотификацией после коммита — похожие проблемы.
ИМХО, в случае dating-портала этой проблемой можно особо не заморачиваться
C>>Еще одно замечение, Hibernate не поддерживает кэширование для определенных мэпингов (использующих SQL-формулы, хранимые процедуры для взятия коллекций и т.п.) — так что тут надо внимательнее. ДГ>В книжке "JP with Hibernate" таких деталей не нашёл. Где они описаны?
В доке по Hibernate кэшированию уделен только один раздел, и там не очень-то много информации. В основном, тут просто надо использовать здравый смысл и чтение исходников Чаще всего, еще можно ставить простые эксперименты.
ДГ>Интересует и настройка стратегии сброс/репликация (доки по конкретному кешу, так?)
Да, это все зависит от кэша. Вы какой appserver собираетесь использовать? Если JBoss — то лучше сразу смотри JBoss Cache. Он очень просто интегрируется с Hibernate, кстати.
ДГ>и какие данные Hibernate гоняет между нодами (доки по Hibernate?).
В случае инвалидации — кэш будет гонять только нужные нотификации.
В случае репликации — немного сложнее. Hibernate сначала "разбирает" объекты (или коллекции) на составные части, то есть, объект не кладется тупо в кэш (чтобы не положить туда случайно половину базу данных по транзитивным зависимостям). Поищи в исходниках Hibernate по слову "disassemble" — там все просто.
Затем "разобраный" объект кладется в кэш, причем он может класться как один большой кусок или как набор свойств — регулируется настройкой hibernate.cache.use_structured_entries. Обычно лучше ставить ее в false.
Кэш уже дальше сам думает что с объектом делать. При репликации, скорее всего, объект будет сериализован и передан по сети.
При взятии объекта из кэша — делаются обратные действия.
C>>PS: давно хочу статью написать про кэширование ДГ>Бааальшую? Было бы здорово.
Ага. Надо будет на досуге заняться.
Sapienti sat!
Re[6]: Stateless-сервер на Hibernate: кеширование и вообще
Здравствуйте, Дм.Григорьев, Вы писали:
C>>Тот же Hibernate можно использовать как тупой маппер с результатов SQL-запросов с ничтожным оверхедом. ДГ>Ты имеешь в виду read-only? Это как? Выполняем запрос, закрываем сессию и работаем с detached-объектами?
Нет, можно использовать Hibernate чисто как mapper с результатов запросов на объекты. У нас тогда будет почти нулевая разница между использованием и неиспользованием Hibernate.
Sapienti sat!
Re[4]: Stateless-сервер на Hibernate: кеширование и вообще
C>Популярное заблуждение. Тот же Hibernate можно использовать как тупой маппер с результатов SQL-запросов с ничтожным оверхедом.
Я говорю в том числе и о личном опыте общения с NHibernate. Его механизм сохранения, при котором он норовит оббежать весь граф объектов, находящихся в сессии, чтобы найти один измененный и сохранить его — меня, честно не очень порадовал с точки зрения оверхеда.
Расширяется он тоже не слишком легко как-то. Не, ну я рад, что вам понравилось, и действительно, много хорошего в нем есть, но все же не стоит его идеализировать.
Никакой NHibernate и никакой другой автоматический тул не построит вам в точности тот запрос, который, может быть, вам как раз и нужен.
Re[6]: Stateless-сервер на Hibernate: кеширование и вообще
Igor Trofimov wrote: > C>Популярное заблуждение. Тот же Hibernate можно использовать как тупой > маппер с результатов SQL-запросов с ничтожным оверхедом. > Я говорю в том числе и о личном опыте общения с NHibernate. Его механизм > сохранения, при котором он норовит оббежать весь граф объектов, > находящихся в сессии, чтобы найти один измененный и сохранить его — > меня, честно не очень порадовал с точки зрения оверхеда.
А что в этом плохого? Обычно это пренебрежимо малая величина — сессии
должны быть короткими.
Если же у нас в сессии куча данных, то переписываем на StatelessSession
или используем ручной flush. Лично мне этого делать не приходилось.
Да, для readonly-сессий вообще flush нужно отключать.
> Расширяется он тоже не слишком легко как-то. Не, ну я рад, что вам > понравилось, и действительно, много хорошего в нем есть, но все же не > стоит его идеализировать.
Я просто пока не видел больше никакого другого ORM такого же уровня.
Хотя, естественно, Hibernate не идеален (а NHibernate еще более неидеален).
> Никакой NHibernate и никакой другой автоматический тул не построит вам в > точности тот запрос, который, может быть, вам как раз и нужен.
Так и не надо — [N]Hibernate позволяют писать пользовательские
SQL-запросы. Мне лично это приходится делать ну ооочень редко.
Posted via RSDN NNTP Server 2.1 beta
Sapienti sat!
Re[7]: Stateless-сервер на Hibernate: кеширование и вообще
C>А что в этом плохого? Обычно это пренебрежимо малая величина — сессии C>должны быть короткими.
Эта величина зависит не от длительности сессии, а от количества загруженных в сессию экземпляров.
C>Если же у нас в сессии куча данных, то переписываем на StatelessSession C>или используем ручной flush. Лично мне этого делать не приходилось. C>Да, для readonly-сессий вообще flush нужно отключать.
Именно. То есть "тупо" уже не получается — надо приседать. Ручной flush кстати, точно так же оббегает все.
>> Никакой NHibernate и никакой другой автоматический тул не построит вам в >> точности тот запрос, который, может быть, вам как раз и нужен. C>Так и не надо — [N]Hibernate позволяют писать пользовательские C>SQL-запросы. Мне лично это приходится делать ну ооочень редко.
Вот об этом я и говорил — что для большого процента кода он вполне годится, а для маленького, где важна оптимальность — придется писать руками.
Думаю, понятно, что "пользовательские запросы" NHibernate — это уже совсем не ORM, о котором волнуется топикстартер.
Re[8]: Stateless-сервер на Hibernate: кеширование и вообще
Здравствуйте, Igor Trofimov, Вы писали:
C>>А что в этом плохого? Обычно это пренебрежимо малая величина — сессии C>>должны быть короткими. iT>Эта величина зависит не от длительности сессии, а от количества загруженных в сессию экземпляров.
Это я и имею в виду.
C>>Если же у нас в сессии куча данных, то переписываем на StatelessSession C>>или используем ручной flush. Лично мне этого делать не приходилось. C>>Да, для readonly-сессий вообще flush нужно отключать. iT>Именно. То есть "тупо" уже не получается — надо приседать. Ручной flush кстати, точно так же оббегает все.
Ставишь interceptor (реализуешь org.hibernate.Interceptor), в нем переопределяешь метод findDirty — и усе. Вчера как раз пришлось так сделать
Еще можно пошаманить с AbstractFlushingEventListener — унаследоваться от него, и добавить свою логику. Тогда вообще можно граф не оббегать.
Кстати, хорошей идеей тут было бы использование модификации байт-кода. В Hibernate оно уже есть для поддержки lazy properties — надо еще добавить, чтобы оно умело помечать объекты при их изменении. Можешь написать им feature request.
C>>Так и не надо — [N]Hibernate позволяют писать пользовательские C>>SQL-запросы. Мне лично это приходится делать ну ооочень редко. iT>Вот об этом я и говорил — что для большого процента кода он вполне годится, а для маленького, где важна оптимальность — придется писать руками. iT>Думаю, понятно, что "пользовательские запросы" NHibernate — это уже совсем не ORM, о котором волнуется топикстартер.
Просто таких запросов получается не особо много.
Кстати, могу рассказать интересную шутку. У меня в программе в первой версии мы использовали жуткие SQL'и, которые находили некие свободное "вакансии" и людей, которые их могут занять. SQLи работали примерно по 2 секунды после всех танцев с бубнами вокруг оптимизатора.
В следующей версии правила подбора усложнились, и я сделал черновой вариант с обычными циклами в Java-коде. Потом у меня отпала челюсть — он работал быстрее запроса к БД примерно в два раза за счет того, что ВСЕ нужные объекты обычно уже лежали в локальном кэше Hibernate. А потом еще добавили предвычисления и их кэширование — оно вообще все стало мгновенным.
С тех пор я всячески стараюсь все по максимуму использовать кэш Hibernate и вообще все возможные кэши.
Sapienti sat!
Re[9]: Stateless-сервер на Hibernate: кеширование и вообще
C>>>А что в этом плохого? Обычно это пренебрежимо малая величина — сессии C>>>должны быть короткими. iT>>Эта величина зависит не от длительности сессии, а от количества загруженных в сессию экземпляров. C>Это я и имею в виду.
Вы имеете в виду, что сессия не должна загружать много объектов? Не слишком ли много ограничений? Логике лучше знать, сколько и каких данных ей нужно загрузить, обработать и сохранить. И при этом этой логике не хочется часто вспоминать об NHibernate и оптимизировать свои действия для него.
C>Ставишь interceptor (реализуешь org.hibernate.Interceptor), в нем переопределяешь метод findDirty — и усе. Вчера как раз пришлось так сделать C>Еще можно пошаманить с AbstractFlushingEventListener — унаследоваться от него, и добавить свою логику. Тогда вообще можно граф не оббегать.
Да, так и живем. Это называется "тупо используешь — и оно очень быстро работает"?
C>Кстати, хорошей идеей тут было бы использование модификации байт-кода. В Hibernate оно уже есть для поддержки lazy properties — надо еще добавить, чтобы оно умело помечать объекты при их изменении. Можешь написать им feature request.
Спасибо, я лучше как-нибудь так... Хибернейтовские прокси, кстати, у меня нормально не работают — вешают отладчик при попытке просмотра объекта.
iT>>Думаю, понятно, что "пользовательские запросы" NHibernate — это уже совсем не ORM, о котором волнуется топикстартер. C>Просто таких запросов получается не особо много.
Я не говорил, что их много. Их мало. И именно поэтому не нужно волноваться об эффективности ORM — критичные запросы все равно писать руками. Что-то я уже повторяюсь.