Кеширование в WordPress
Сегодня я хочу рассказать об использовании механизма кэширования в WordPress. Начну издалека.
Сторонники MT (Movable Type) часто приводят один довод в пользу «своего движка». Речь идет о том, что МТ генерирует т.н. статику. Получается, что повторная компоновка страницы не требуется и это сокращает нагрузку на сервер и ускоряет выдачу страницы браузеру.
Не вдаваясь в технические нюансы и не совсем точный термин «статика», можно сказать что по сути аргумент вполне весомый. Как ни крути, а статическая страница, которая заранее подготовленна и не требует дополнительной обработки PHP и/или запросов к базе данных, всегда будет отдаваться сервером быстрее.
Однако, если копнуть чуть глубже, то мы столкнемся с ситуацией, когда «статику» невозможно использовать. Например, если мы введем счетчик количества просмотров страницы, то получается вся страница, или хотя бы этот блок, будет динамическим. Иначе он просто перестанет работать.
С другой стороны, какой смысл генерировать заново страницу, когда она в общем-то один раз уже сформировалась и не меняется с момента публикации/редактирования?
В итоге напрашивается вывод: нужно использовать динамику и статику выборочно. Все эти размышления меня натолкнули на мысль попробовать использовать кэш WordPress'а для статики. И хотя это не 100-процентная статика (вроде html-файла), но суть точно такая же, даже лучше, поскольку можно задать время жизни кэшированной страницы.
Что такое кэш
Для начала рассмотрим базовые понятия.
Предположим у нас есть какая-то php-функция. Она вызывается каждый раз при загрузке страницы. Функция - это может быть плагин, виджет, WordPress-функция или ваша собственная. Это не важно.
function func1 ($args) {
операторы функции
echo $result; // вывод результата
}
Предположим, что наша функция выполняет обращение в БД, потом что-то еще анализирует и после выводит результат (echo). Теперь предположим, что агрументы функции не меняются или меняются редко. Получается, что результат всегда возвращается один и тот же: для первого посетителя, второго, десятого и т.д.
Вот для того, чтобы не выполнять сам блок функций, мы можем использовать кэш.
Работает это так:
function func1 ($args) {
$cache_key = 'func1'; # ключ
если кэш с $cache_key есть, то выводим его
и выходим
операторы функции
# вывод результата
echo $result;
добавляем данные в кэш с ключом $cache_key
}
Вначале мы создаем уникальный ключ для кэша, после этого проверяем есть ли этот кэш: если есть, то выводим и выходим из функции. Если нет, то выполняем функцию и в конце добавляем в кэш с нашим ключом выведенные данные.
Если мы зададим время жизни кэша, скажем 15 минут (стандарт для WordPress), то данная функция за это время не будет выполнятся - готовый результат сразу будет браться из кэша.
Функции кэша
Для работы с кэшем нам понадобятся всего две функции.
wp_cache_get() - получение кэша.
wp_cache_add() - добавление кэша.
Есть два важных параметра, которые нам следует особо оговорить: ключ и время жизни.
Ключ должен быть уникальным, иначе вместо нужных данных вы получите данные из другой функции. Правда есть один нюанс - если у вас одна или две функции, то можно было бы ключ придумать, но если функций много, то лучше этот процесс автоматизировать.
За основу можно взять функцию, возвращающую имя выполняемой функции: __FUNCTION__. Но у нас есть еще аргументы, поэтому в ключ мы должны добавить и их. Не вдаваясь в подробности, сразу скажу, что можно использовать функцию serialize(), которая возвращает переменную в специальном строковом формате.
Эти данные мы оформим в md5, чтобы получить строковое значение, состоящее из цифр и английских букв.
После этого мы можем проверить наличие кэша и если он есть, вывести его.
function func1 ($args) {
$cache_key = md5(__FUNCTION__ . serialize($args));
if ( $output = wp_cache_get($cache_key) )
return print($output);
Как видите код довольно простой и универсальный. Конечно же, если вы добавите другие аргументы, то вам нужно их указать в ключе.
Буферизация вывода
Данные кэша мы помещаем в переменную $output, но возникает вопрос, а откуда они вообще берутся? Так вот, в PHP есть возможность не выводить сразу в браузер данные (echo или print), а перед этим создать некий буфер, куда поместятся все выводимые данные. Уже после этого вывести весь буфер целиком в браузер.
ob_start(); // начало буферизации echo или print сколько нужно echo ob_get_flush(); // вывели весь буфер
Таким образом мы можем получить весь вывод, как результат функции ob_get_flush. То есть, как вы уже поняли именно его мы и будем добавлять в кэш.
Добавление данных в кэш
Код:
// время жизни кэша в секундах 60 * 3 = 3 минуты $myexpire = 60 * 3; wp_cache_add($cache_key, ob_get_flush(), '', $myexpire);
Можно не указывать $myexpire - в этом случае используется стандартные 15 минут.
Теперь объеденим все куски в единое целое.
function func1 ($args) {
$cache_key = md5(__FUNCTION__ . serialize($args));
if ( $output = wp_cache_get($cache_key) )
return print($output);
ob_start(); // начало буферизации
операторы функции (echo или print)
// время жизни кэша в секундах 60 * 3 = 3 минуты
$myexpire = 60 * 3;
wp_cache_add($cache_key, ob_get_flush(), '', $myexpire);
}
Вот такой у нас получился каркас для любой функции WordPress.
Кеширование в виджетах
В прошлых выпусках мы рассматривали виджеты и вполне логично, рассмотреть кеширование в них.
Код будет отличаться совсем не намного. Разница только в том, что виджеты, которые используют опции ($options), мы будем добавлять в ключ кэша:
$options = get_option('widget_my_widget');
$cache_key = md5(__FUNCTION__ . serialize($options));
Если функция без echo
Бывают функции, которые не выводят результат в виде echo, а возвращают значение через return. В этом случае буферизация нам не нужна, поэтому ob_start(); нужно вообще удалить, а кэш добавлять так:
wp_cache_add($cache_key, <strong>$out</strong>, '', $myexpire); return <strong>$out</strong>;
То есть результат мы помещаем в $out, которая и идет в кэш.
Контроль эффективности
Чтобы увидеть эффективность кэширования, добавьте в конец footer.php такие строчки.
<?php echo ' | MySQL: ' . get_num_queries() . '/'; timer_stop(1); ?>
Это отображает количество запросов MySQL и время выполнения. На своей тестовой машине, где включены полсотни плагинов и больше двадцати виджетов, без кэширования создается примерно 120 запросов MySQL. После включения кэша количество сокращается до 50-70, а после применения глобального кэширования - всего 10-20. Мой рекорд - 8 запросов. ![]()
Если кэш не работает
Возможна ситуация, что у вас вообще отключен кэш. Если это так, то проверьте в файле wp-config.php наличие таких строк.
# define('DISABLE_CACHE', '');
define('ENABLE_CACHE', '');
Если у вас моя сборка WordPress, то в файле приведены комментарии, так что не ошибетесь. Также у вас должен быть каталог /wp-content/cache/ и у него должны стоять права на запись. Обычно это 777.
«Глобальное» кэширование
Теперь мы подходим к самому интересному. Кэш WordPress'а так устроен, что можно кешировать практически всё. Например мы можем закешировать весь сайдбар.
В начало файла sidebar.php пишем код:
<?php
$cache_key = md5('mytheme-sidebar');
if ( $output = wp_cache_get($cache_key) )
return print($output);
ob_start();
?>
После этого идет код сайдбара, а в конце файла выводим кэш:
<?php $myexpire = 60; // время жизни кэша в секундах wp_cache_add($cache_key, ob_get_flush(), '', $myexpire); ?>
Таким образом наш сайдбар будет генерироваться раз в 60 секунд.
Кэширование основных текстов
Сейчас мы сделаем то, чем так гордятся MT-шники. ![]()
Признаться я долго не мог придумать каким образом сделать ключ для основного текста (тот, что в цикле TheLoop). Привязываться к номеру записи, или рубрики или еще чему-нибудь неэффективно, потому что потребуется переделка шаблона. Решение пришло неожидано и оно оказалось простым и изящным: ключ нужно генерировать на основе $wp_query (подробности и продолжение). Эта переменная содержит структуру (массивы и объекты) из которых и выводятся данные в цикле TheLoop.
Итак, перед
<?php if (have_posts()) : while (have_posts()) : the_post(); ?>
Мы добавляем:
<?php $cache_key = md5(serialize($wp_query)); if ( $output = wp_cache_get($cache_key) ) return print($output); ob_start(); ?>
А в конце уже привычный:
<?php $myexpire = 60 * 3; // время жизни кэша в секундах 60 * 3 = 3 минуты wp_cache_add($cache_key, ob_get_flush(), '', $myexpire); ?>
Вуаля! Вот мы получили «статику» на WordPress. ![]()
Что нельзя кэшировать
Один пример я уже привел - счетчики, которые сразу же отображают результат. Наверное можно было бы как-то исхитриться и выводить их, скажем через js или iframe. Или попробовать как-то разделить кэширование на части, чтобы отображать статику из кэша, а динамику геренировать отдельно. Тут все зависит от многих вещей, поэтому универсального способа нет.
Бессмысленно кэшировать простой html-код. Например счетчики-рейтинги или рекламу. То есть в кеш нужно добавлять только тот код, который:
- PHP;
- создает запросы к БД;
- выполняет сложные/длительные вычисления.
Ну и конечно же бессмыслено делать кэш для малопосещаемого сайта. По моим прикидкам, кэширование оптимально где-то от 60-100 хитов в час.
Возможные проблемы при работе с кэшем
Собственно это даже не проблемы, а особенность. Например, вы разрабатывате функцию или добавляете её в свой шаблон. Но, поскольку ключ кэша не изменился, то вы сразу не увидите и изменения. Выход очень простой - отключить кэш на время отладки. Для этого раскоментируйте строчку «define('DISABLE_CACHE', '');» в wp-config.php. Этим самым вы отключите кэш.
Также возможны проблемы при комментировании - если вы закешировали страницу целиком, вместе с комментариями, то новые комментарии появятся только после обновления кэша. Поэтому подходить к этому нужно осторожно.
- Подключение кода SAPE для WordPress
- Плагин Clutter Free
- Плагин «Ушки»
- Новый плагин «ушки»
- Плагин социальных закладок
- Плагин «Anti-XSS attack»
- Плагин “Сноски”
- Расширенный визуальный редактор WordPress
- Плагин «Ключевые слова»
- MaxCache: кэш для WordPress. Максимальное ускорение WordPress. Снижение нагрузки в 100 раз
- Плагин My Category Order
- Плагин Russian Date
- Аналоги WordPress-плагинов в MaxSite CMS
- Плагины WordPress, которые вы используете на своем блоге
- Плагин Anti Spam Image. Новый подход


:cool:
Полезно и элегантно! Спасибо, будем пользоваться :idea:
Ниасилил...попробую с утречка!
А вот я так и не осилил этот кэш. В результате живу без него :(
Как только я включаю кэш, сразу начинают появляться новые файлы в папке /wp-content/cache/
Они появляются и появляются, постепенно их становится очень много, один раз эта папка разрослась до 200 мегабайт! Экперименты не помогли, так и отключил :(
Как пользователь Movable Type могу сказать (смайл), что статика, которую по-другому и не назовёшь — это не единственный довод в пользу MT. Хотя он, бузусловно, очень сильный.
Немного более подробно про него мы говорили в блоге Султана Салпагарова.
Имхо задумываться о таких вещах стоит только когда сервак уже затрещит от нагрузки, а мне такое пока не грозит :(
Спасибо, будем экспериментировать:smile:
Очень полезная информация
Недавно тоже разбирался с кешированием, решил отключить до того момента пока не подниму посещаемость потомучто блог находится все ещё в процессе активной разработки и кеш только мешает
Гораздо более эффективно использовать Wp-Cache2 plugin (http://mnm.uib.es/gallir/wp-cache-2/). Могу сказать, что это реально помогает.
Блог, с кол-вом трафика ~100-200К на wordpress'е без кэширования создаёт нагрузку где-то 4-6уе; при использовании плагина - нагрузка падает до значения меньше единицы.
Очень хороший плагин - рекоммендую всем людям, кроме тех, кто использует всякие трейд-скрипты для обмена траффика, а-ля AT3. Вся проблема из-за того, что в шаблон нужно вставлять этот грёбаный PHP virtual(). Хотя это можно обойти использую bash, но это уже костыль.
Удачи! :cool::cool:
Неплохой совет по совершенствованию Wp cache2 можно найти на блоге AskApache.com : http://www.askapache.com/wordpress/wp-cache-speed-hack.html
Чекайте :arrow:
Наконец то. Спасибо! Из - за отсутствия полноценной инфы по кэшу вордпресса собрался переходить на другую CMS. Переход отменяется!
Осталось "победить" редактор в админке и к WP вообще ни каких претензий не будет.
Ещё раз спасибо.
kirizoid, мы не могли бы пообщаться на эту тему плотней в ICQ? У меня как раз блог под 100К начинает заваливаться, сервер очень мощный, канал ещё мощней, встроенный кэш судя по всему работает, плагин который ты советуешь ставил, с ним хуже получается, стоит ATX, но тем не менее папка cache исправно наполняется. Судя по трафу одно дело делаем
, стукни если не затруднит 191/052*482
Хм, попробуем плагин
Для перехода на КМС с блога рекомендую Джумлу. Кстати кэш в ней встроеный, а еще есть компонент для кэширование полных страниц.
О джумле можете почитать на сайте Joomla! Україна
Сам юзаю джумлу паралельно с водпресом, но ее для порталов или просто больших сайтов.
З.Ы.: Автору сайта большой респэкт за идею сопоставления друпала, джумлы, вордпреса (тип, тоже в алфавитном порядке
)
Интересно. Сейчас проэкспериментируем с глобальным.
>Осталось "победить" редактор в админке и к WP вообще ни каких >претензий не будет.
Чего его побеждать. Поставил себе Windows Live Writer или Blog Jet - и пиши без проблем из оффа а потом грузи в блог.
Я использую плагин "WP-Cache 2.0" для кэширования страниц на своем Блоге. Замечательный плагин. Удобный интерфейс. Гибкие настройки.
Florid,
а не возникает ли проблем сплагином кеширования при работе с сейпом (sape) и прочими системами, когда нужно установить сторонний php код ?
При использовании данного хака пропадает подвал и сайдбар, даже если их закешировать
Atari: Проблема с sape и сторонними вполне вероятна.
Так же как вероятна при использовании глобального кеширования.
Бот sape оказался не в состоянии найти данные при кешировании.
Вот в прошлый раз я как то уже изучал эту информацию и мне особо это дело не было нужно, а вот теперь время пришло и для меня тоже актуален кэш. И прочитав второй раз у меня возникло сразу несколько вопросов.
1. А вот по умолчанию, если я включаю кэш в файле конфига, то кэш как работает? Что кэшируется? Как узнать?
2. Народ говорил, что разрастается папка cache и я помню у меня была подобная проблема. Это в связи с чем она разрастается? Можно ли как то уменьшить её объём? Это как то регулируется. А то 200MB это всё-таки уже не шутки, с учётом того, что BD всего лишь 10MB.
3. Вот это вот ваши хуки объяснения как что закешировать, они параллельно со стандартным кэшированием (я про п.1) происходят или нет?
Круто конечно, но можно по пунктам, а? :wink: ну не силен я так в PHP как для этого текста, к своему стыду, стараюсь изучать но пока "читать" так не научился к сожалению. Ранее я видел в рассылках (сейчас не найдя этой статьи) было подробное объяснение, как и что делать в WP 2.1 для того, чтобы работал там кеш, сейчас же у меня WP 2.3.3 и тоже очень хотелось бы снизить нагрузку на сервер, но как это сделать? :idea: Пожалуйста сделайте версию для действий или разъясните подробнее. Заранее спасибо!
Как сделать чтобы кешировалось навсегда?
Без Expiry time
А что вы можете сказать в пользу или против плагина Hyper Cache?