PHP, Cache_Lite
В этой статье я напишу о том, как кэшировать данные на стороне сервера в файлы.
Кэширование может помочь значительно снизить нагрузку на ваш сервер, при большом количестве обращений к вашим скриптам.
В этой статье будет приведен пример кэширования рейтинга пользователей из базы.
Кэширование можно применять не только в описанном в данной статье случае. Думайте логически, где конкретно в вашем проекте нужно применять кэширование.
Прежде чем сразу пытаться применить описанный в этой статье способ кэширования на своем проекте, советую сначала полностью понять принцип работы.
В статье будет использоваться специальный класс. Он справляется с основной задачей кэширования, проверяет целостность созданного кэша и имеет дополнительные настройки. Если вам будет надо, то вы сможете написать и свой класс, когда поймёте принцип работы кэширования.
Создадим скрипт для тестирования класса для кэширования
1. Создадим базу пользователей
Код: Выделить всё
CREATE TABLE IF NOT EXISTS `scores` ( `id` int(9) AUTO_INCREMENT, `uid` int(9), `score` int(10), PRIMARY KEY (`id`), UNIQUE KEY `uid` (`uid`)) ENGINE=MyISAM DEFAULT CHARSET=utf8; -- Наполним базуINSERT INTO `scores` (`uid`,`score`) VALUES(1,1000),(2,1300),(3,800),(4,700),(5,1500);
2. Напишем скрипт scores.php, выводящий рекорды из базы
Код: Выделить всё
<? $db_host="localhost"; // обычно не нужно изменять$db_user="user"; // имя пользователя БД$db_password="pass"; // пароль БД$db_name = "name"; // имя БД mysql_connect($db_host, $db_user, $db_password) or die (mysql_error());mysql_select_db($db_name) or die (mysql_error());mysql_query("SET NAMES 'utf8'"); $query = 'SELECT * FROM `scores` ORDER BY `score` DESC LIMIT 3;';$sql = mysql_query($query); if (mysql_num_rows($sql)) { while ($sql_data = mysql_fetch_array($sql)) { echo $sql_data['uid'].' - '.$sql_data['score'].'<br />'; }} // https://flapps.ru/forum/?>
Этот скрипт довольно простой. В нем выполняется несложный SQL запрос и нет ресурсоемких вычислений.
Для примера он подойдёт. Представьте, что вместо простого SQL запроса в этом скрипте происходит сложный SQL запрос, объединяющий несколько таблиц и сильно нагружающий сервер баз данных и, например, после выбора этих данных, в PHP происходят сложные вычисления, которые тоже сильно нагружают сервер. Либо в нашем случае, это может быть обращение к ВКонтакте API, для получения имен пользователей.
Теперь представьте, что этот скрипт будет вызван не одним пользователем, а сразу 10 пользователями одновременно в одну секунду. Или даже одновременно 1000 пользователями. Нагрузка на сервер будет очень большой.
При обращении к этому скрипту в одну и ту же секунду, пользователи получают одну и ту же информацию. Так почему бы не выполнить этот скрипт 1 раз и записать его результат в файл, а потом просто выдать всем пользователям данные из этого файла, не выполняя сложный SQL запрос и не проводя сложных вычислений? Так и нужно сделать. Это и будет кэшированием.
Если бы пользователи получали в ответ от сервера разную информацию, например которая зависимосит от их ID, то кэширование может не подойти.
При кэшировании нужно учитывать, чтобы данные были актуальными. Если кэшировать данные на 1 час, то за это время информация в кэше и в базе может стать разной.
Частоту обновления кэша нужно подбирать конкретно к вашей задаче. Нужно выбрать грань между актуальностью и нагрузкой на сервер.
Иногда кэширование имеет смысл делать даже на несколько секунд.
Если ваш проект очень сильно посещаем, например 1000 человек в секунду делают одинаковый запрос, который возвращает одинаковый результат, то можно делать кэширование на несколько секунд. Произойдёт одна ресурсозатратная операция, а остальные запросы будут взяты из кэша.
Думайте логически, стоит ли кэшировать какие-либо данные, что будет ресурсозатратнее - выводить данные напрямую или кэшировать.
Применение кэширования
1. Скачиваем PHP класс Cache_Lite
Это можно сделать на странице http://pear.php.net/package/Cache_Lite/download
Нужно выбрать «For manual installation only».
В этой статье будет описана работа с последний на данный момент версией Cache_Lite 1.7.15.
2. Извлекаем папку Cache
В этой папке находятся классы, которые будут выполнять всю работу:
- Lite
-- File.php
-- Function.php
-- NestedOutput.php // необязательный файл
-- Output.php
-Lite.php
Я разархивировал эту папку в корень основной директории.
Если на вашем сервере нет PEAR, то нужно так же скачать библиотеку PEAR http://pear.php.net/package/PEAR/download
На данный момент последняя версия 1.9.4.
Из архива вытаскиваем файлы PEAR.php и PEAR5.php и кладем в папку Cache.
3. Создадим папку cache_files
В эту папку будут сохраняться файлы кэша.
Я поместил её в корень основной директории.
4. Изменим скрипт scores.php
Добавим в скрипт scores.php вывод времени выполнения скрипта
Код: Выделить всё
// чтобы видеть в какое время скрипт был выполненecho 'Скрипт был выполнен '.date('H:i:s').'<br />';
Получим код:
Код: Выделить всё
<? require_once('Cache/Lite/Output.php');$options = array( 'cacheDir' => 'cache_files/', // куда сохраняются файлы кэша 'caching' => true, // можно отключить кэширование 'lifeTime' => 5, // время жизни кэша в секундах 'writeControl' => true, // проверка, что файл кэша был создан корректно 'readControl' => true, // проверка файла кэша перед его выводом 'fileNameProtection' => false, // кодирование имени файла кэша 'readControlType' => 'md5' // тип контроля кэша);$cache = new Cache_Lite_Output($options); // начинаем кэшироватьif (!($cache->start('score_page','Static'))) { // если файл кэша данного участка существует и его время жизни ещё не прошло, то данные будут выведены из файла кэша, а следующий код не будет выполнен // score_page - название файла кэша // Static - группа кэша $db_host="localhost"; // обычно не нужно изменять $db_user="user"; // имя пользователя БД $db_password="pass"; // пароль БД $db_name = "name"; // имя БД mysql_connect($db_host, $db_user, $db_password) or die (mysql_error()); mysql_select_db($db_name) or die (mysql_error()); mysql_query("SET NAMES 'utf8'"); $query = 'SELECT * FROM `scores` ORDER BY `score` DESC LIMIT 3;'; $sql = mysql_query($query); echo 'Скрипт был выполнен '.date('H:i:s').'<br />'; if (mysql_num_rows($sql)) { while ($sql_data = mysql_fetch_array($sql)) { echo $sql_data['uid'].' - '.$sql_data['score'].'<br />'; } } // заканчиваем кэширование $cache->end(); } // https://flapps.ru/forum/?>
Каждые кэшируемые данные должны иметь свое название. В этом коде всего один участок кэширования, который называется score_page. Static - это название группы кэша. Группа необходима для массовой работы с несколькими кэшами, например массовое удаление.
5. Запустим скрипт
После запуска в папке cache_files появится файл cache_Static_score_page
Обновите страницу. Данные будут взяты из этого файла. В этом можно убедиться, глядя на время когда был выполнен скрипт.
Можно так же обновить данные в базе и убедится, что в кэше они не будут обновлены.
Увеличим время жизни кэша, например до 30 секунд
Код: Выделить всё
'lifeTime' => 30,
Код: Выделить всё
UPDATE scores SET score=1600 WHERE uid=1;UPDATE scores SET score=1900 WHERE uid=3;
Пример кэширования нескольких частей на разное время
Код: Выделить всё
<? require_once('Cache/Lite/Output.php');$options = array( 'cacheDir' => 'cache_files/', // куда сохраняются файлы кэша 'caching' => true, // можно отключить кэширование 'lifeTime' => 5, // время жизни кэша в секундах 'writeControl' => true, // проверка, что файл кэша был создан корректно 'readControl' => true, // проверка файла кэша перед его выводом 'fileNameProtection' => false, // кодирование имени файла кэша 'readControlType' => 'md5' // тип контроля кэша);$cache = new Cache_Lite_Output($options); // начинаем кэшировать// время жизни кэша берется из настроек вышеif (!($cache->start('page_part_1','Static'))) { echo 'Первый участок кода был выполнен '.date('H:i:s').'<br />'; $cache->end();} // поменяем время жизни кэша$cache->setLifeTime(15);if (!($cache->start('page_part_2','Static'))) { echo 'Второй участок кода был выполнен '.date('H:i:s').'<br />'; $cache->end();} // https://flapps.ru/forum/?>
Очистка кэша
Очистить кэш можно просто удалив файлы кэша из папки cache_files либо с помощью php скрипта.
Для удаления файла кэша можно использовать
Код: Выделить всё
$cache->remove('score_page', 'Static');
Либо
Код: Выделить всё
$cache->clean('Static');
Описанного в этой статье должно быть достаточно, чтобы понять как работает кэширование, и какие возможности по уменьшению нагрузки на сервер оно дает.
Эта статья не раскрывает полного функционала класса Cache_Lite.
Скачать файлы из этой статьи https://flapps.ru/example/server_cache.zip
Например, если нужно закэшировать только одно строковое значение переменной:
Код: Выделить всё
<?require_once('Cache/Lite/Output.php');$options = array( 'cacheDir' => 'cache_files/', // куда сохраняются файлы кэша 'caching' => true, // можно отключить кэширование 'lifeTime' => 5, // время жизни кэша в секундах 'writeControl' => true, // проверка, что файл кэша был создан корректно 'readControl' => true, // проверка файла кэша перед его выводом 'fileNameProtection' => false, // кодирование имени файла кэша 'readControlType' => 'md5' // тип контроля кэша);$cache = new Cache_Lite_Output($options); if ($data = $cache->get('value1')) { echo $data;} else { $data = 'Data of the value1'; $cache->save($data);} // https://flapps.ru/forum/?>