Кеш: Как 3 функции значительно ускорят ваш сайт
У меня на сайте достаточно давно была проблема загрузки главной страницы – из-за отображения большого количества записей из многих рубрик.
Представьте: основные рубрики в табах – это по 7 записей в 5 категориях (где каждая категория – отдельный запрос). Вкладка “Остальное” – это 4 рубрики по 8 записей в каждой (где каждая рубрика тоже отдельный запрос). С учетом того, что WordPress при использовании new WP_Query
и/или get_posts
делает не по одному запросу, а больше, то получается весьма значительное число – больше 60 запросов к базе.
Естественно, это значительно замедляло загрузку страницы. Генерация была на уровне 5 секунд и кол-во общих запросов – 83.
Из-за того, что у меня на VDS от Avihost стоит не Apache, а чистый Nginx, то большинство плагинов кеширования у меня просто не работало. И я решил написать свою собственную систему частичного кеширования.
Под частичным кешированием я подразумеваю сохранение в кеш лишь отдельной части сайта, предположим, кусок главной страницы, отвечающий за вывод списка записей. Мне необходимо сохранить динамичность всего остального контента.
И я написал 3 функции, которые:
- получает из базы, формирует html и возвращает тот контент, который мне нужен;
- делает сброс кеша и создает новый при сохранении/создании любой записи в админке;
- делает проверку при загрузке страницы свежести кеша, и если он “свежий”, то показать его, в ином случае – см. пункт 2.
Всего 3 функции, которые уменьшили кол-во запросов с 83 до 19 и время генерации страницы с 5 секунд до 0.550.
Так как мой код строго завязан на своем контенте, я покажу вам костяк, который вы сможете доработать и использовать у себя.
Итак, для начала создайте в папке шаблона папку cache/
, а в ней пустой файл cache.txt
.
Далее определяете тот блок контента, который вы хотите кешировать (преположим, это будет список записей). Копируете весь этот код из home.php (к примеру) в отдельный временный файл, вместо него в home.php вставляете функцию
<?php cd_home_content() ?>
Потом открываете файл functions.php шаблона. И вставляете туда следующее:
function cd_home_get_content(){
ob_start();
// здесь ваш код получения записей в лупе, который вы скопировали во временный файл из home.php
$data = ob_get_clean();
return $data;
}
// Заново генерируем кеш, если обновили какой-то пост
add_action('save_post', 'cd_home_cache_flush');
function cd_home_cache_flush($post_id){
$file = dirname(__File__). '/cache/cache.txt';
$data = cd_home_get_content();
if (is_writable($file)) {
// я убрал здесь проверки на то, записался ли кеш или нет. У меня все записывается, потому оставил как есть
$handle = fopen($file, 'w+');
fwrite($handle, $data);
fclose($handle);
}
if( ! is_admin())
return $data;
else
return $post_id;
}
// Непосредственно вывод контента - или из кеша, или только что сгенерированного
function cd_home_content(){
// Готовим переменные
$file = dirname(__File__). '/cache/cache.txt';
$last_mod = filemtime($file);
if ( $last_mod < ( time() - 86400 ) ) { // наш кеш устарел - прошло больше 24 часов с момента его генерации, делаем все заново
echo '<!--[Cache: Creating cache for '.time().'...]-->';
echo cd_home_cache_flush($file);
}else{ // все в порядке, пользуемся кешом
echo '<!--[Cache: From cache '.$last_mod.']-->';
echo file_get_contents($file);
}
}
Собственно, по комментариям в коде все понятно, я надеюсь.
86400 – это сутки в секундах, через это время кеш будет принудительно сбрасываться, если вы ничего не публиковали/не изменяли на сайте. Эта проверка необязательна, но я решил оставить.
Минус такого способа кеширования – долгое время сохранения поста. Но так как это в админке происходит и пользователи ничего не замечают, то я не считаю такую проблему не критичной.
Внедрил тоже самое – но для блока комментариев и ключевых слов в сайдбаре. Точно также сделал 3 функции, а обработчик кеша (сбрасыватель и генератор) повесил на add_action( 'wp_insert_comment', 'cd_sidebar_cache_flush', 20, 2);
Все отлично работает – убрал еще 3-4 запроса (стало 15) и время генерации упало до 0.413 сек.
Вот это не совсем ясно. В какой-такой временной файл? куда его ложить, с каким расширением и как обозвать?
И для новичка непонятно как быть когда кешируемых выводом несколько. Какие части кода для functions.php надо добавить для других выводов.
Новички либо пользуются плагинами, либо сами пытаются разобраться опытным путем)
Вы копируете этот код, чтобы потом использовать в cd_home_get_content(). Никуда не надо его сохранять, понимайте мои слова как скопировать в буфер обмена.
А если несколько, то лучше всего для каждого блока создавать 2 функции
cd_xxx_get_content()
иcd_xxx_content()
, где вторая используется в шаблоне для вывода, а первая – для генерации контента. Также надо будет внести именения вcd_xxx_cache_flush()
, чтобы сбрасывался и заново генерировался кеш для другого блока.Я бы попробовал создать еще одну функцию, только с другим названием.
Вы правы – другая функция (или даже другие 3 функции, чтобы меньше заморачиваться).
Вмеcто вызова 2 функций:
можно вызывать только 1:
Да, можно и так :)
Я подправил код в записи.
Ради интереса внедрил кеширования для блока комментариев в сайдбаре. Этот комментарий отчасти является тестом обновления кеша :)
Ха, только что обнаружил, что спам тоже сбрасывает кеш сайдбара :)
)))))))))))))))
на самом деле ob_ – не очень хорошее решение… во всяком случаи в связке WP+BP вызывает иногда проблемы.. и если вы предлагаете “клиенту” разный контент (к примеру, вошел пользователь или нет) – то будут косяки)
можно просто сохранять результат работы – в текстовый файл в папке cache и затем выдавать клиентам..
Так у меня так и сделано – результат работы… А возможность регистрации и авторизации я никому не даю :) Я же для своего сайта писал это решение. Теперь вот думаю посмотреть в сторону memcache…