Кэширование на стороне сервера

Уроки по PHP, Javascript и т.п.
Ответить
Аватара пользователя
Александр
Создатель сайта
Создатель сайта
Сообщения: 4574
Зарегистрирован: 27 сен 2009, 16:45

Кэширование на стороне сервера

Сообщение Александр »

Кэширование на стороне сервера
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;
и после этого несколько раз выполним скрипт scores.php.



Пример кэширования нескольких частей на разное время

Код: Выделить всё

<? 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');
Удалит все файлы кэша группы 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/?>
Alazaur
Разработчик
Разработчик
Сообщения: 1001
Зарегистрирован: 16 окт 2011, 20:25

Re: Кэширование на стороне сервера

Сообщение Alazaur »

Вот это труд :shock:
Ответить