Полукеш, или Суперкеш. Простая реализация

Приветствую. Назрела очень серьезная тема. Будем подготавливать проекты к большим нагрузкам, снижению трафика и экономии ресурсов. И все это достаточно просто.

Суперкеш. Сжимай и ускоряй

Что, по вашему мнению, означает понятие кэш в веб-разработке? Примерно следующее – подготовка каких-то готовых малоизменяющихся блоков, чтобы не прорисовывать их каждый раз, а выдавать пользователю сразу и обновлять по мере изменения. Это может быть уже кусок готового HTML, или отдельная таблица в базе данных, содержащая какие-то агрегированные данные.

Если наш проект уже потребляет достаточно ресурсов – мы можем пытаться его оптимизировать, или частично закэшировать.

 

Давайте рассмотрим еще одно понятие – компиляция. Компиляция – преобразует выполняемый код к понятным для компьютера формату. Но такой код будет недоступен, неудобен для редактирования и разработок.

В большинстве проектов кешированию подлежит некий результат запроса, включенный в шаблон. Кешу назначается некое время жизни, по истечении которого – нужно снова залезть в базу данных и снова скомпилировать готовый шаблон. При этом некоторые элементы шаблона могут быть динамическими. Например, рейтинг – мы можем обновлять раз в час, а авторизированного пользователя – выдавать в зависимости от текущей сессии. Шаблон кэша в зависимости от событий – может дать команду к принудительному обновлению кэша.  В чем тут особенность? Компилированный шаблон создается на лету при обновлении страницы и тут же сохраняется в кэше для дальнейших запросов.

Это самый обычный кэш, в нем нет ничего нового. Разработать такого рода программу – не составляет большого труда. Можно отдельные куски хранить в компилированных htmlфайлах, проверять время обновления файла и удалять при необходимости его обновления.

Как по вашему, что представляет из себя идеальный кеш? Наверное – он отрабатывает моментально быстро. Он занимает меньше места за счет gzipсжатия и он сам по себе меньше весит, т.к. в нем удалены лишние пробелы и ненужности html (вроде закрывающегося тега optionили tr). Да. Это хорошо компилированная статическая htmlстраница. Наш процессор к ней – не нагружается абсолютно, т.к. phpдаже не участвует в ее отклике.

Теперь вы знаете, о чем я хочу дальше сказать. Это будет суперкэш. Мы будем кешировать всю страницу целиком!

Да. Этот вариант подходит для статических сайтов, где резонно кешировать всю страницу целиком. Или для сайтов, где большая часть контента доступна без регистрации и без динамического содержимого. Для случаев, если пользователь таки авторизируется – мы отдадим стандартную страницу без кеширования, или с обычным кешированием, как это было подготовлено выше.  Еще вариант – создать javascript, который будет управляться через php и вносить изменения в блоки страницы. То есть будем отслеживать только наложения на страницу. Ведь авторизация, оформление заказа – не должны быть доступны для поисковых роботов, а динамическое число просмотров статьи – роботам также параллельно.

Зато какие преимущества? При обращении к странице – к базе данных мы не обращаемся, не ждем подключения. Мы не парсим html, Мы не сжимаем и не оптимизируем его. Мы просто берем готовый сжатый файл html и просто его выдаем при помощи echo.

Полностью отказаться от скриптов очень сложно. Ведь пользователь может передать нам данные при помощи GET POST, заполнить корзину вдруг, или авторизоваться. Он также может в поисковой форме ввести новое слово. Мы же не можем для каждого слова в поисковой форме сделать кэш…

Но таким образом мы можем покрыть большую часть пришедших с поисковиков посетителей. Что при хорошей посещаемости – приведет к увеличению скорости загрузки (а поисковики это очень любят), уменьшению трафика. И вообще будет очень хорошо.

Как мы будем этого добиваться практически – вопрос отдельный. Но реализуемый. Он очень схож с обычным кэшированием.  Если у нас есть админка – после кардинального изменения – будем чистить кеш. Кеш чистится – удалением всех файлов в директории.

public $cachefolder='cache';
public function clear(){
     if ($handle=opendir($this->cachefolder)){
         while(false !== ($file=readdir($handle))){
             if ($file == '.' or $file == '..') continue;
             unlink($this->cachefolder.'/'.$file);
         }
         closedir($handle);
    }
}

Вопрос следующий у нас возникает.  Если изменения на сайт вводятся чаще, чем просматриваются – на обновление всего кэша целиком уйдет очень много ресурсов. Да. Это правда. Если при добавлении новости – у нас обновляется кэш на всех 500 страницах, а новости добавляются каждый час. При этом посещаемость сайта сама по себе не велика – большого проку от такого кеширования не будет. Будет резон при обновлении кэша на 30 самых популярных страницах. Но такое решение допустимо, только если мы ведем счетчик посещений и можем выявить самый популярный контент

А вот если периодически – примерно раз в неделю – нужно внести изменения в ряд товаров – резонно делать обновление кэша только после последнего действия. Можно даже делать это по расписанию – каждый день.

Такая реализация допустима для большого ряда сайтов, обновляемых раз в неделю или реже.

Следующий вопрос – который у нас возникает – в адресе. Как хранить названия директорий, если мы подразумеваем хранение кэша в плоском каталоге?.. Нужно каким-то образом Хешировать полный путь (то есть создать неповторимую комбинацию от пути обращения).  Желательно, чтобы функция была не затратной по ресурсам. На этот счет отлично подходит старая добрая MD5.

Для компиляции страницы – нам подойдет следующий код

public function refresh_page($link){
   $cachefile=$this->cachefolder.'/'.md5($link).'.gz';
   if (file_exists($cachefile)) unlink($cachefile);
   if (isset($_SESSION)){
      $temp=$_SESSION;
      unset($_SESSION);
   }
   $text=file_get_contents('http://'.$_SERVER['HTTP_HOST'].'/'.$link);
   if (!$text)return false;
   file_put_contents($cachefile,gzencode($this->compress_html($text),9));
   if (isset($temp))$_SESSION=$temp;
   return true;
}
private function compress_html($compress){
   return preg_replace('/\s+/',' ',$compress);
}

В двух словах – мы прогоняем страницу, как бы это сделал пользователь. Без сессии, GETа и Поста.

Заодно используем функцию для удаления лишних пробелов. В html– между тегами более одного пробела – обрезаются и создают лишний мусор, необходимы только для красивого оформления для разработки. Если вы используете утопические двойные пробелы в скриптах – выделите их в отдельный javascript файл. Еще на хостинге должны быть включены обращения к файлам через get_contents. Если отключены - используйте curl или прямой вызов через require предварительно передав нужные параметры в SERVER

Вроде бы ничего сложного. В исполнительном файле – в самом начале пишем примерно следующий код

if (empty($_SESSION) and empty($_GET) and empty($_POST)){
    if (file_exists($file='cache/'.md5($_SERVER['REQUEST_URI']).'.gz')){
       $page=file_get_contents($file);
       header('content-encoding: gzip');
       header('vary: accept-encoding');
       header('content-length: '.strlen($page));
       die($page);
    }
}

Вроде бы ничего хитрого, стандартные костыли и заголовки.

Далее – раз в день – прогоняем скрипт по всему списку файлов.

На закуску встает еще один вопрос. Если посещаемость сайта – мизерная, а файлов – куча – пересоздавать кучу файлов раз в день – может быть накладно. Да. Возможен и такой исход. Все индивидуально.

Мы также можем предусмотреть условие, по которому будем обновлять кэш или нет. Логика такая – если файл с кэшем лежит – значит кэш – актуальный. Значит – если список обновляемых путей сходится со списком существующих кэшей – обновлять кэш не надо. Под это правило не попадает расчет, если что-то на странице показывает текущую дату, или зависит от курса валюты.

Одно могу сказать – супер кэш лучше чем обычный кэш. А значит – у вас есть серьезное конкурентное преимущество.

  • Автор: kosmom
  • Рейтинг: 0
  • Просмотров: 753
  • Комментариев: 0
  • Создан: 22.08.2013 12:34

Комментарии (0)