Кэширование на серверном уровне. Автоматизация кэширования. Уменьшение количества запросов
Условное кэширование
Сброс кэша
Кэширование на серверном уровне
Кэширование XHR-запросов Довольно часто приходится наблюдать ситуацию, когда время создания страницы на сервере занимает несколько (десятков) секунд. Разбор характерных причин возникновения такого и возможных решений таких ситуация мы рассматривать не будем (он выходит за рамки текущей книги), но есть ряд методов для частичного устранения проблем «медленных» страниц. Речь идет о простейшем кэшировании созданных HTML-документов.
Обычно (в случае динамических сайтов) при создании HTML-страницы осуществляются десятки или сотни запросов к базе данных, подключаются десятки (или сотни) различных библиотек, и не всегда можно корректно справиться с проблемами количества запросов на уровне самой базы данных или ускорителя компиляции исполняемого кода (например, eaccelerator).
На виртуальных хостингах (когда ресурсы одного сервера могут делить десятки или сотни различных сайтов) для относительно простого сайта (который не предполагает значительного взаимодействия с пользователем) стоит рассмотреть возможность создания кэша готовых HTML-страниц. Что это такое?
Отдаем закэшированный документ
Каждый конкретный пользователь при запросе на сервер получает готовый HTML-документ, который включает в себя только клиентскую (не зависящую от состояния сервера) динамику, которая функционирует в браузере пользователя (и хранится в его кэше), а не на сервере. Соответственно, мы можем фактически смоделировать тот же браузерный кэш, только серверными средствами.
Для более детального примера давайте рассмотри следующим код, отвечающий за простейшее серверное кэширование, из Web Optimizer:
/* проверяем, можем ли отдать закэшированный документ */
if (!empty($this->cache_me)) {
/* переводим адрес документа в реальное имя файла */
$this->uri = $this->convert_request_uri();
$file = $this->options['page']['cachedir'] . '/' . $this->uri;
/* проверяем, существует ли файл и достаточно ли он актуальный */
if (is_file($file) &&
$_SERVER['REQUEST_TIME'] - filemtime($file) <
$this->options['page']['cache_timeout']) {
$content = @file_get_contents($file);
/* проверяем, сжат ли файл */
if (!empty($this->options['page']['gzip']) &&
substr($content, 0, 8) == "\x1f\x8b\x08\x00\x00\x00\x00\x00") {
/* если сжат, то выставляем соответствующие заголовки */
$this->set_gzip_header();
}
/* отдает закэшированное содержимое */
echo $content;
/* и закрываем PHP-процес */
die();
}
}
Переменная $cache_me может формироваться на основе множества параметров (в том числе, части URL, которые нужно или не нужно кэшировать, пользовательские агенты и роботы, для которых можно отдавать кэшированные версии страниц, и т.д.). Стоит также отметить, что просто создать файла с именем, равным текущему URL страницы невозможно: в нем встречаются недопустимые символы (/, ?), которые нужно трансформировать при сохранении на файловой системе.
Создаем закэшированный документ
Но мы рассмотрели процесс выдачи закэшированного документа, а каким образом он появляется на жестком диске? Процедура сохранения файла немного проще, и может быть записана следующим образом (код из Web Optimizer):
/* определяем, нужно ли нам сохранять закэшированную версию документа */
if (!empty($this->cache_me)) {
/* формируем имя файла */
$file = $options['cachedir'] . '/' . $this->uri;
/* проверяем, есть ли такой файл и устарел ли он */
if (!is_file($file) ||
$_SERVER['REQUEST_TIME'] - filemtime($file) >
$options['cache_timeout']) {
/* записываем новое содержимое в файл */
$fp = @fopen($file, "a");
if ($fp) {
/* блокируем файл от конкурентных попыток записи */
@flock($fp, LOCK_EX);
/* удаляем содержимое и перемещаемся на начало файла */
@ftruncate($fp, 0);
@fseek($fp, 0);
@fwrite($fp, $this->content);
@fclose($fp);
}
}
}
Правильно настроенное кэширование на серверном уровне способно сэкономить время ваших посетителей (и тем самым поднять конверсию сайта) и сэкономить серверные ресурсы (при использовании каких-либо распределенных мощностей).