Кеширование в друпал

Главные вкладки

Аватар пользователя andribas@drupal.org andribas@drupal.org 28 декабря 2010 в 11:30

Статья незаконченная, на праздниках буду проводить benchmark и постараюсь реализовать идею, которую здесь описал.

Итак, Вы установили друпал, настроили сайт и запустили.
Но некоторые страницы отдаются медленно или сервер не справляется с нагрузкой.
Что можно сделать в друпале, чтобы ускорить отдачу?

1. Рассматриваем установку с nginx + php_fpm, где Apache отсутствует.

2. Включаем кеширование блоков в друпал, кеширование страниц пока выключено.

3. Помещаем opcode в кеш, для этого используется APC. Drupal со всеми модулями занимает порядка 40 Мб в памяти.

4. Помещаем все таблицы cache* в память - здесь варианта 2 - CacheRouter или Memcache API. Каждый из этих модулей имеет свои преимущества - в CacheRouter реализовано много хранилищ - Вы можете использовать разные для разных таблиц, БД, APC, memcached, file. Однако, если говорить о высокой нагрузке, то хранилище будет memcached. Преимущество Memcache API заключается в том, что этот модуль умеет хранить в памяти кроме cache* таблиц еще и sessions - как показали наблюдения за сайтом, в эту таблицу много пишется, поэтому в кеше работа с ней будет быстрее и снизит нагрузку.

В принципе уже это позволит сайту работать быстро, и большинство устроит. Что же можно сделать еще? Вот какие есть варианты:

1. Использовать boost - этот модуль позволяет кешировать страницы для анонимных пользователей на диск.

Для кого предназначен: для анонимов

Как работает: при запросе анонимом страницы, если ее нет в кеше, она генерируется, помещается в кеш и следующий запрос будет обслужен из кеша.

Преимущества: достаточно легко настроить, работает очень быстро, не потребляет память.

Недостатки: в этом модуле реализован достаточно сложный механизм валидации, т.е. в БД ведется таблица boost_cache_relationships, и при любых изменениях на сайте (точнее для которых этот модуль имеет поддержку - views, voting api и т.д.) он начинает производить валидацию контента - например при изменении ноды проверяется главная, таксономия, nodereference, views. Рассмотрим типичный случай - в блоке слева как на этом сайте последний контент, или что еще хуже, последний комментируемый контент. Понятно, что эта валидация сотрет все страницы из кеша.
Даже если помещать сам кеш boost в память, как я описывал - создать раздел в linux shared memory, то все равно куча INSERT,DELETE для таблицы boost_cache_relationships будет нагрузкой, и кеш будет жить недолго.

2. Использовать Varnish - этот модуль, также как и буст для анонимов.

Для кого предназначен: для анонимов

Как работает: также как и буст. Отличие заключается в том, что кеш создается не в друпале, а в самой reverse-proxy.

Преимущества: работает очень быстро.

Недостатки: труднее настроить, требует pressflow, патча ядра друпал 6 или друпал 7 (к слову сказать, в pressflow был сделан backport из друпал 7 - это не их задумка с сессиями). В отличие от boost здесь нет валидации, при любом изменении информации (нода, коммент и т.д.) происходит полный сброс кеша - вызывается varnish_purge_all_pages().
По идее, если бы буст не делал валидацию, отличий между этими модулями нет, только в реализации. Для нашего примера с блоком на друпал.ру этот модуль также даст мало пользы.

3. Модуль authcache - этот модуль действует по другому.

Для кого предназначен: для всех

Как работает: Сначала страница попадает в кеш. Затем делается вызов AJAX для тех блоков, где реализован callback, и блоки обновляются.

Преимущества: кеш дольше живет.

Недостатки: не реализована поддержка многих модулей, запрос на обновление происходит со стороны клиента. Нет стабильности.

Вот в общем-то и все альтернативы. Идеей для этого поста стало обсуждение на http://drupal.ru/node/52716 - почему бы не "подружить" nginx с друпал по аналогии с varnish?
Как оказалось, не только я с Crea до этого додумался, и есть заявление о том, что это частично реализовано - http://technosophos.com/content/53900-speedup-nginx-drupal-and-memcache-... - сделан форк memcache, чтобы хранить таблицу cache_pages без сериализации - дело в том, что nginx умеет брать из memcache, но не умеет туда класть. Но решение это частное, для конкретного сайта.

Идея проста - по аналогии с буст или memcache сохраняем страницу для анонимов и помещаем ее в кеш, который будет доступен nginx. В nginx пытаемся сначала взять из кеша, если не получилось, то идем в друпал.
По идее, в этот модуль нужно добавить поддержку статистики из буста, а проверку на анонимность можно взять оттуда же, т.к. варниш с друпал 6 не работает. Либо, взять за основу проверку varnish, т.к. в друпале 7 эта возможность будет у всех.

Однако, этот метод также не спасет от purge_all при любом обновлении.

Однако более многообещающим звучат рассуждения самого создателя nginx:
доклад Игоря Сысоева о работе Рамблер идея SSI - https://dev.vega.ru/doc/library/Conferences/RIT-2007/001-011_01.1.pdf

Эта идея получше, но не до конца понятна и объединяет в себе самое лучшее, что есть в вышеописанных модулях:

1. Создаем 2 таблицы кеша - блоки и страницы.
2. В кеш блоков помещаем блоки как анонимов, так и зарегистрированных пользователей.
3. В кеш страниц помещается страница с SSI включениями вместо блоков - т.е. само содержимое страницы, без шапки, левой, правой панели.

При таком подходе, если обновится 1 нода, то она повлечет за собой изменения блоков, но контент других страниц останется прежним, поэтому при запросе уже кешированной страницы, последняя будет отображена корректно. Этот способ будет работать корректно для кеширования нод, но не таксономии, views или каких-то landing pages, где куча контента из разных источников.
Проблемы, которые могут возникнуть:
1. Блоки должны быть в кеше как в друпале - глобально, по роли, по пользователю.
2. Контекст блока - для отображения корректной информации в блоке может быть использован контекст - пользователь, сама нода, ее таксономия, что еще? - для этого нужно предусмотреть что-то навроде boost_cache_relationships - при изменениях контента зависимые блоки по идее должны быть удалены из кеша.

Вот примерный сценарий:
1. Пользователь открывает страницу на друпал.ру с материалом node/5 (нода, не таксономия).
2. В кеш попадает сама нода и все блоки, которые видит пользователь.
3. При открытии следующей ноды node/6 страница также генерируется, но блоки берутся из кеша друпала.
4. При возврате к первой ноде node/5 она полностью берется из кеша (проверка для всех SSI - если хоть 1 блока нет, то брать не из кеша, а идти в друпал за полной страницей)
5. Дальше пользователь создает новый контент, левый блок "Новое на сайте" становится не актуальным, поэтому в друпале сбрасывается кеш блоков.
6. Теперь, если мы обратимся к node/5, то контент будет взят из друпала (т.к. нет блоков в кеше) - при этом саму страницу в кеше можно и не обновлять, т.к. она не изменилась - нужны только блоки.
7. Однако, если после этого открыть node/6, то она будет взята из кеша - потому что обращение к node/5 обновило кеш блоков.

В многопользовательской среде, при отсутствии персональных блоков пользователя на внутренних страницах (читай - нодах) все будет красивее, если блок закеширован не для пользователя, а для роли - тогда при удалении этого блока из кеша он будет туда помещен первым пользователем, а второй пользователь получит уже целиком страницу из кеша (т.к. для всех SSI нашелся блок в кеше).

Однако, у ноды может быть такой вот неприятный контекст: блок "еще в этом разделе" с выводом последних нод того же термина таксономии, что у ноды. В этом случае контекст блока будет зависеть от ноды, здесь, пожалуй, может помочь только authcache.

Тем не менее, сквозные блоки для пользователей - например, блок групп, в которые вступил пользователь на groups.drupal.org, для всего сайта - например, "Новое на сайте" на этом сайте, будут отлично кешироваться и кеш страниц не будет постоянно чиститься. Используя стратегию LRU memcached сам будет выкидывать из кеша то, что никому не нужно.

В частности, для сайта друпал.ру таких нехороших контекстов для блоков нет - поэтому закешировать можно очень хорошо, осталось придумать как связать идею authcache с этими нехорошими контекстами, и возможно ли хранить кеш блоков (а возможно, и страниц - авторизованный пользователь может оставить коммент, неавторизованный - нет) по двум парам ключей - ID пользователя, ID блока - но это, думаю, возможно если вести вспомогательную таблицу и обрабатывать ее к примеру во встроенном perl nginx?

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

Что касается идеи nginx вместо varnish, то она вполне реализуема, так что попробую начать с нее.

Комментарии

Аватар пользователя seaji seaji 28 декабря 2010 в 17:45

Позвольте полюбопытствовать, а Вам это нужно для конкретной задачи или просто для интереса?
Если для конкретной задачи, то хотелось бы узнать текущие показатели в цифрах и те показатели, которые Вы хотите достичь.

Аватар пользователя Crea Crea 28 декабря 2010 в 19:05

См. мой модуль Advanced Panels Cache - гибкое кеширование любых участков сайта при условии, что сайт делается на основе модуля Panels.

К сожалению, никак не дойдут руки допилить модуль - сейчас он экспериментальный. Вообще я хочу отвязать его от Memcache с помощью своего апи, и кеш будет, например, в MongoDB.

Аватар пользователя andribas@drupal.org andribas@drupal.org 10 ноября 2015 в 11:47

"seaji" wrote:
Позвольте полюбопытствовать, а Вам это нужно для конкретной задачи или просто для интереса?
Если для конкретной задачи, то хотелось бы узнать текущие показатели в цифрах и те показатели, которые Вы хотите достичь.

Вообще задача конкретная - добиться максимальной производительности на имеющихся ресурсах.
В данный момент нагрузка не напрягает, но хотелось бы иметь запас. Цифры могу показать такие:

но это был пик, обычно нагрузка меньше.

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

"Crea" wrote:
См. мой модуль Advanced Panels Cache - гибкое кеширование любых участков сайта при условии, что сайт делается на основе модуля Panels.

Был приятно удивлен, что у Вас уже есть готовый модуль, который кеширует и делает валидацию, основываясь на контексте, посмотрю внимательней как Вы это сделали, спасибо.

Аватар пользователя seaji seaji 30 декабря 2010 в 1:10

"<a href="mailto:andribas@drupal.org">andribas@drupal.org</a>" wrote:
Вообще задача конкретная - добиться максимальной производительности на имеющихся ресурсах.

Понимаете, производительность должна быть достаточной, а не максимальной. Поверьте моему опыту максимальная производительность в 90% случаев не нужна.
Я не просто так спросил про конкретные цифры. Ваши изыскания имеют большое значение, но только с теоретической точки зрения.
Практически это очень мало кому пригодится потому как лично у меня на шаред хостинге пятый друпал свободно держит полторы тысячи уников в сутки. Скажите, кому нужно больше?

Аватар пользователя Crea Crea 30 декабря 2010 в 3:20

Анонимных можно и больше с бустом каким-нибудь
вот чтобы для зарегистрированных летало - это куда сложнее..

Аватар пользователя seaji seaji 30 декабря 2010 в 12:13

Поймите меня правильно, я не отговариваю.
В целях обучения очень важно разобрать как и что работает.
Просто я хотел сказать, что работодатель не поймет зачем ему тратиться на решение проблем, которые могут возникнуть где-то в будущем, а могут и не возникнуть Smile

Аватар пользователя Виктор Степаньков ака RxB Виктор Степаньк... 30 декабря 2010 в 12:23

"seaji" wrote:
Просто я хотел сказать, что работодатель не поймет зачем ему тратиться на решение проблем, которые могут возникнуть где-то в будущем, а могут и не возникнуть :)

Вспоминается 100000000 онлайн, на сайте где нынешняя посещаемость около 1000 просмотров в сутки.
Но уважаю ТС, не буду сравнивать с синкорой.