Когда я писал статью о Smaty, я не думал, что она вызовет столько внимания со стороны программистов. Как выяснилось шаблонизаторы, все еще остаются актуальной темой.
В комментариях к этой статье, зашел разговор и о кэшировании. Вопрос кэширования данных волнует многих начинающих программистов. Походив по форумам и сообществам, я понял тема актуальныя. :)
Конечно существуют готовые решения для кэширования данных, но я предложу свою реализацию. Она довольно проста и поможет понять сам механизм кэширования.
Мы не будем кэшировать старницу целиком, данный подход устарел. В реалиях “двух нулей” активно используется кэширование отдельных блоков. А если еще точнее, то мы будем кэшировать только чистые данные, т.е. никакого HTML.
И так, код:
<?php
abstract class Cache
{
public function __construct() {}
abstract function save($value, $valueID);
abstract function load($valueID, $time);
abstract function delete($valueID);
}
?>
И класс кэширования в файл:
<?php
class CacheFile extends Cache
{
private $path;
public function __construct($path = 'cache')
{
$this->path = $path;
}
public function save($value, $valueID)
{
$str_val = serialize($value);
$file_name = $this->pathCache($valueID) .
$this->nameCache($valueID);
$f = fopen($file_name, 'w+');
if (flock($f, LOCK_EX)) {
fwrite($f, $str_val);
flock($f, LOCK_UN);
}
fclose($f);
unset($str_val);
}
public function load($valueID, $time)
{
$file_name = $this->getPathCache($valueID) .
$this->nameCache($valueID);
if (!file_exists($file_name)) return false;
if ((filemtime($file_name) + $time) < time()) {
return false;
}
if (!$data = file($file_name)) return false;
return unserialize(implode('', $data));
}
public function delete($valueID)
{
$file_name = $this->getPathCache($valueID) .
$this->nameCache($valueID);
unlink($file_name);
}
private function pathCache($valueID)
{
$md5 = $this->nameCache($valueID);
$first_literal = array($md5{0}, $md5{1}, $md5{2}, $md5{3});
$path = $this->path . DIRSEP;
foreach ($first_literal as $dir) {
$path .= $dir . DIRSEP;
if (!file_exists(site_path . $path)) {
if (!mkdir(site_path . $path, 0777)) return false;
}
}
return site_path . $path;
}
private function getPathCache($valueID)
{
$md5 = $this->nameCache($valueID);
$first_literal = array($md5{0}, $md5{1}, $md5{2}, $md5{3});
return site_path . $this->path . DIRSEP .
implode(DIRSEP, $first_literal) . DIRSEP;
}
private function nameCache($valueID)
{
return md5($valueID);
}
}
?>
Константы site_path и DIRSEP задаем в конфигурационном файле, следующим образом:
<?php
define ('DIRSEP', DIRECTORY_SEPARATOR);
define ('site_path', dirname(dirname(__FILE__)) . DIRSEP);
?>
Методы getPathCache($valueID) и pathCache($valueID) нужны для уменьшения количества файлов в одном каталоге, путем построения дерева каталогов. Это существенно увеличит скорость чтения при большом количестве файлов кэша.
Пример использования:
<?php
function megaCalculation()
{
//Здесь происходят ресурсоемкие операции
//и ВОЗВРАЩАЕТСЯ какое-либо значение
}
$cache = new CacheFile('cache');
//Кэшируем на 10 минут
if (!$var = $cache->load('mega', 10*60)) {
$var = megaCalculation();
$cache->save($var, 'mega');
}
?>
Вот и все. Кэширование - это просто. :)
Внимательный читатель спросит: “А зачем было делать класс Cache?” Все просто. Кэширование бывает не только на файлах. И в этом классе мы описываем обязательные методы для всех производных классов.
Можно еще кэшировать при помощи MemCache, баз данных (например, Berkeley DB) и т.д. Но это уже тема для следующих статей. :)







Интересно, спасибо. Только код читать неудобно: overflow: hidden мешает…
SHAman, пожалуйста. Я отредактировал - сделал переносы. Теперь все должно быть нормально.
Не, не нормально… Может,
сделать overflow: auto? Тогда скрольчики хоть появятся, а то из исходника читать неудобно. Конечно, можно из RSS... но все равно не айс:) (IE7, 1024x768)Спасибо, за замечание. У меня монитор широкоформатный (1280х800) поэтому и неудобств не видел…
Я как очень внимательный читатель спрашиваю, а может данный класс нужно было сделать синглетоном? Врядли в проекте необходимо куча объектов класса CacheFile.
Valentin Gernovich, согласен. =)
В рабочем примере так и есть. Но здесь я решил упростить ))) Наверное зря. Переделаю.
Valentin Gernovich, зачем тут Singleton ? ихмо Registry рулит)))
admin,
1. тему с константаки не осилил, особенно с DIRSEP.
2. Вообщето использовать на прямую CacheFile плохо… допустим есть необходимость перейи на Memcache. как быстро ты сделаешь?
3. По больному счёту в классе Cache болжно быть 3 метода(load,save,delete). Покажи пример метода pathCache или nameCache для Memcache…
Patrick,
мало букв не осилил? Или что? DIRSEP, это так сказать псевдоним системной константы DIRECTORY_SEPARATOR. Просто системное название довольно длинное. =)
Второе, Патрик, пример учебный так сказать. Этот пример создан для того, чтоб показать, что кэширование это просто. [Ctrl+H :)]
На третий вопрос отвечу позже. В статье по MemCache ;)
З.Ы. По поводу Singleton… При наличии реестра, Singleton не отменяется. ИМХО, лучше всего в данном случает использовать и то, и то. Registry - для удобства доступа, Singleton - для защиты “от дураков”.
мало букв не осилил? Или что? DIRSEP, это так сказать псевдоним системной константы DIRECTORY_SEPARATOR. Просто системное название довольно длинное. =)
Зачем только?
З.Ы. По поводу Singleton… При наличии реестра, Singleton не отменяется. ИМХО, лучше всего в данном случает использовать и то, и то. Registry - для удобства доступа, Singleton - для защиты “от дураков”.
Баян! Ты правда так думаешь?
Patrick, ну что мне тебе на это сказать?
Да, я действительно так думаю, иначе не написал бы этого.
Ну тогда тебе подойдёт:
Использование одиночек и тестирование. Использование паттерна Registry как альтернативы одиночкам.
Инверсия зависимостей при проектировании Объектно-Ориентированных систем
Управление зависимостями в PHP-коде
ЗЫ последнее ты должен был слышать на конфе)))
Patrick, спасибо за ссылки. Да, признаю - переборщил немного =)
А линки действительно хорошие… сижу - читаю.
Постепенно разговор переходит из темы конкретного примера, в тему ООП проектирования и применения патернов :)
Пока лучше не отвлекайся на идеальное решение, пиши про кэширование в память, в БД, и еще куда только возможно. Сосредоточься на алгоритмах. А потом объедини в один пакет, где все будет реализовано по грамотному.
PS Я DIRECTORY_SEPARATOR в своих проектах переопределяю в констатну DS, так еще лаконичнее и удобочитаемо.
Спасибо, но я пока что в кэшировании не нуждался. А так в мемориз :)
cyberfox, на здоровье! Скоро будет продолжение =)
[...] своей первой статье о кэшировании, я рассказывал о кэшировании информации в файлы. Данный тип кэширования можно использовать на всех [...]
День добрый.
Почему не HTML? Что за блоки?
Что за вечное сияние чистых данных в отрыве от HTML?
vasa_c
Что за блоки?
Как правило web-страница состоит из блоков….
Что за вечное сияние чистых данных в отрыве от HTML?
Кэш не должен влиять на View. Ему должно быть пофиг какой шаблон этими данными воспользуется!
ИМХО использовать “кэшированный” HTML(т.е. не чистые данные), следует в случае если в последующем будет использоваться SSI
>Как правило web-страница состоит из блоков….
Ага, из HTML-блоков )
>Кэш не должен влиять на View.
View, это хорошо, но браузеры пока не знакомы с паттернами, а знакомы только с HTML. И только его можно выдавать (если, конечно, не хотите нагрузить клиента xslt-преобразованием).
Все эти данные нужно пропускать через шаблоны, что будет есть лишнее время, а смысл кеширования тогда в чем?
Хотя, ладно, может быть я и загнул. Кешировать можно не только HTML, но и просто результаты вычислений.
Но по большому счету в классе увидел только сохранение/получение переменных, что само по себе хорошо, но еще не полноценный кеш.
По хорошому, кеш получив запрос данных, должен проверить их наличие и актуальности и если надо самостоятельно провести вычисление и сохранение данных.
Даже функция set здесь по большому счету не нужна.
vasa_c, я рад, что не придется переубеждать, что кэшировать HTML это плохо, если проект часто меняет и содержимое и возможно оформление. Что сейчас для всяких стартапов, занятие актуальное.
На счет того, что страница состоит из HTML-блоков, это так, но в определенной абстракции. И эта абстракция не для программистов, а для кодеров или верстальщиков. =)
Странно, что вы не заметили, но кэш получив запрос здесь проверяет наличие данных и их валидность (правда только по сроку хранения). ИМХО, валидация содержания кэша убъет его скорость и универсальность полностью, так что пока от такого изощрения, я воздержусь. =)))
А вот ваша фраза: и если надо самостоятельно провести вычисление и сохранение данных меня просто убила! Ага! =)
Кэш должен только кэшировать и все. Иначе гибкость вашей системы летит ко всем чертям. У вас появится куча зависимостей и т.д. и скелет системы закостенеет и … она вымрет, как мамонты. :)
З.Ы. Спасибо, Патрику, за ответу на вопросы пока я был вдали от компа. ))))
Да, совсем забыл vasa_c почитайте мою следующую статью о кэшировании, может станет более понятной моя идея.
Кэш должен кэшировать!!!
Модель извлекать данные!!!
Кэш и Модель должны пересекаться в контроллере!!!
ИМХО!!!
To: Patrick
Ого! Прям Маяковский!
И прАльно!!!
Землю крестьянам! Заводы рабочим!!!
И чтоб они пересекались только в баре!
>На счет того, что страница состоит из HTML-блоков, это так, но в определенной абстракции.
Это не абстракция, это суровая реальность. Какой бы движок не был супер-пупер абстрактный и невооброзимо паттерный, на выходе всё равно должен быть банальный html.
>валидация содержания кэша убъет его скорость и универсальность полностью
Под валидацией я имел ввиду всё ту же проверку времени. Только со стороны самого кеша.
Универсальность это хорошо, но здесь эта универсальность дошла до того, что это уже и не совсем кеш, а просто хранение переменных (ну еще иногда с проверкой по времени).
>Кэш должен только кэшировать и все.
Да. Но здесь он не кеширует. Здесь кеширует внешний код, которой просто использует данную либу для сохранения данных
ЗЫ. Вообще в абстрактных системах, которые решают абстрактные задачи на абстрактно-чистых данных, кеша быть не должно.
Так как он решает проблемы только грубого реального мира — экономию реальных ограниченных ресурсов.
И в этом грубом мире браузеры показывают только html. И получение html с помощью преобразования данных на основе шаблона так же трудоемкая задача.
Почему он не может кешироваться?
Причем тут модели, разные шаблоны? Это совершенно из другой оперы.
vasa_c, супер!
Может поделитесь примером кода правильного кэша?
To: all
Может, кто-нить ответит господину vasa_c, а то у меня аж дар речи пропал )))
Ладно, не буду утруждать вас своими глупыми речами.
Всего хорошего.
vasa_c, не нужно обижаться. Простите, если задел (у меня бывает :) )
Вы лучше поделитесь, примерами хорошего кэширования. Это будет интересно всем.
А я не обижаюсь. Я от рождения не обидчивый, а долгое пребывание на форумах окончательно притупило это чувство :-D.
Я не пришел делиться примером правильного кеша. И не собирался говорить “вот мой правильный кеш, а ваш — д.мо”.
Я просто задал несколько вопросов, чтобы может быть кто-нибудь над чем-нибудь задумался и ничего больше.
А то, что кто-нибудь мне может ответить, пока у Вас пропал дар речи, я, скорее всего, уже слышал от других, читал в книгах и реализовывал сам :)
vasa_c, я рад, что вы по прежнему с нами =)
И в продолжении:
>>>>На счет того, что страница состоит из HTML-блоков, это так, но в определенной абстракции.
>>Это не абстракция, это суровая реальность. Какой бы движок не был супер-пупер абстрактный и невооброзимо паттерный, на выходе всё равно должен быть банальный html.
Вы меня все же не поняли. Что такое абстракция?
>>Под валидацией я имел ввиду всё ту же проверку времени. Только со стороны самого кеша.
Универсальность это хорошо, но здесь эта универсальность дошла до того, что это уже и не совсем кеш, а просто хранение переменных (ну еще иногда с проверкой по времени).
А у меня проверкой времени разве не кэш занимается?
>>Да. Но здесь он не кеширует. Здесь кеширует внешний код, которой просто использует данную либу для сохранения данных
Покажите мне другой подход, на примере.
>Вы меня все же не поняли. Что такое абстракция?
Фиг с ней с абстракцией.
Весь этот флуд я развел только исходя из вашей фразы “мы будем кэшировать только чистые данные, т.е. никакого HTML”. Вот и не понятно, почему HTML считается грязными данными.
>А у меня проверкой времени разве не кэш занимается?
Не совсем. Вычислением времени устаревания и обработкой ситуации с устаревшими данными занимается внешний сценарий.
>Покажите мне другой подход, на примере.
Давайте с HTML пока закончим )
>>Вот и не понятно, почему HTML считается грязными данными.
Из того, что я назвал, данные без HTML чистыми, вовсе не следует, что данные с HTML - это грязные данные. =) Нет, это данные С ОФОРМЛЕНИЕМ. А оно как известно может меняться. Так, что же если мы сделали, где-то жирное выделение, нам весь кэш чистить? А он на некоторых проектах живет ОЧЕНЬ долго. И его новый пересчет может обернуться плохо.
А все из-за тега B. =))
>>Не совсем. Вычислением времени устаревания и обработкой ситуации с устаревшими данными занимается внешний сценарий.
Как это?! вычислением занимается кэш, а вот запуском этих вычислений занимается внешняя программа.
>А оно как известно может меняться
Меняться может всё )
Вот есть у нас система, которая формирует ответ на запрос. Формирует его в несколько этапов. Последний этап - заполнение шаблона данными и получение html.
Собственно, на каждом этапе производятся какие-то вычисления, которые потребляют ресурсы.
Дабы, снизить нагрузку результаты мы кешируем.
Чем последний этап хуже других? Или формирование html легкая задача на сложных шаблонах? Почему не кешировать эти результаты наравне с результатами всех вышестоящих уровней?
Пересчет не должен оборачиваться плохо. Он должен пересчитывать только то, что нужно и только тогда когда нужно.
>вычислением занимается кэш
Вычисление, это формирование тех самых данных, которые храним в кеше.
Именно внешний код выполняет свои мегакулькуляции и вручную их сохраняет в кеше.
Получив из кеша (getValue) false, именно внешний скрипт должен перемегакуалькулировать всё по новой и опять вручную сохранить в кеше.
Кстати, а почему false? Разве false не может быть равноправным данным? Имхо, лучше исключения задействовать.
vasa_c, вы продолжаете гнуть свою линию.
НО, мы с вами говорим о РАЗНЫХ ТИПАХ, кэширования! Оба они хороши, но применяются в различных ситуациях, то кэширование о котором рассказываете вы - это кэширование вывода. Оно менее гибко, но более быстро в отдаче, т.к. отдается уже сформированная страница.
Еще раз повторюсь, мы спорим о разных вещах. :) И обе эти вещи хороши, но они РАЗНЫЕ.
А вот на счет false - вы правы ))) Хотя как знать… надо подумать над этим.
З.Ы. Что-то нашу беседу все игнорируют (
А я как раз пытаюсь понять, почему именно они разные.
Я не имею ввиду кешировать целые страницы в html-файлы.
А именно кешировать отдельные html-блоки. Причем наравне с кешированием данных на всех других уровнях системы.
Можно кэшировать и HTML-блоки, но мне такой подход не нравиться.
Так, например, на сайте некоторый кэш может жить по несколько недель… но при этом, сайт активно развивается и устраивает различные промо-акции и т.д. Некоторые промо-акции требуют частичного изменения дизайна сайта, например, добавление новогодней тематики в канун новогодних праздников. Т.о. велика вероятность, что для данного изменения нам потребуется сбросить кэш, а это лишние тормоза в период промо-акции, что естественно не допустимо.
Так зачем сбрасывать кеш? :)
Кеш для страниц будет просто устаревшим. При запросе он переформируется.
При Вашей же нелюбви к кешированию HTML это формирование будет происходить при каждом запросе.
>>Кеш для страниц будет просто устаревшим.
Это в честь чего???
Например, мы создали кэш сегодня. С временем жизни 2 недели. Через неделю мы изменили некое оформление, но т.к. кэш у нас валиден еще неделю, нам показывается старое оформление. И что мы делаем? Правильно :), сбрасываем кэш. Ч.Т.Д.
У меня нет не любви к кэшированию HTML-кода, когда это рентабельно, я это делаю. Просто в данной статье я взял, на основу те системы, где кэширование HTML-кода не рентабельно. А вы решили будто я противник кэширования HTML вообще ))))
Изменяя оформление, сбрасываем кеш. Либо весь html-кеш, либо только для отдельных блоков.
Но это не значит, что нужно удалять все файлы. Просто отдельно нужно иметь еще метку актуальности для кеша данного типа.
Посчитайте, сколько за ту же неделю будет запросов к сайту.
Вы упорно не хотите меня понимать. Вы хоть раз сталкивались с управлением и сбросом кэша на большом проекте на практике?
Да, сталкивался.
Я упорно понимаю Вас с самого начала.
На кова чорта, прошу прощения, его сбрасывать, вместо того, чтобы пометить неактуальным?
vasa_c, скажите, а как вы собираетесь помечать его не актуальным? При модификации только файлов шаблонов…
А как происходит модификация файлов шаблонов?
Как, как? В любом редакторе, с последующей заливкой на сервер. Это при условии, что у нас нет админ интерфейса по управлению шаблонами.
В случае с
банально смотреть время модификации файла
при
возложить нужные действия на этот интерфейс
Вы чего??? Вы предлагаете, чтоб кэширование еще и за шаблонами следило?
Да.
Проверять данные на актуальность, это прямая обязанность кеширования.
:) Шаблоны это не данные!
Во всторых почему я считаю что данные с HTML это “грязные” данные, да только по тому что помимо HTML есть разного рода XML и т.д.
Но как уже было сказано - ШАБЛОНЫ ЭТО НЕ ДАННЫЕ!. =)))
И как сказал, Патрик, а что вы будете делать если несклько страниц на сайте нужно будет представить еще и в PDF?
Шаблоны - это всего лишь вариант представления данных!
Но это не данные!
Шаблоны не данные. А вот итоговый HTML, это данные. Данные, получающиеся, преобразованием шаблона на основании других входных данных.
Ресурсоёмкого преобразования.
Почему не кешировать эти результаты?
PDF, XML? И что, чем они мешают? Если они так же генерируются на основании каких-то шаблонов, то их тоже кешировать не помешает.
Кешируются не данные. Кешируются результаты.
vasa_c, вы не пробиваемы.
С этим я согласен, но результаты бывают разные.
Но вот когда вы сказали, что кэширование должно следить за состоянием шаблонов - это уже слишком. Не считаете ли вы, что на больших сайтах шаблонов может быть просто гигантское число, особенно когда на сайте предусмотрено несколько тем?
И ваше слежение за шаблонами будет очень ресурсоемким процессом. Или вы и результат слежения будете кэшировать? =)
Какое слежение за шаблонами?
Шаблон это файл на диске.
Он выбирается по каким-то механизмам не относящихся к кешированию.
Потом получаем операцию
+=
вот на этом этапе нужно решит, выполнять её или взять результат из кеша. Если в кеше есть, то нужно проверить актуальность. Проверяется просто - сравнением времен генерации кеша и последней модификации файла.
strip_tag() ? :)
Я имел в виду
“потом получаем операцию”:
[выбранный шаблон] + [входные данные] = [результирующий html]
vasa_c
Все же это уменьшает универсальность данного класса. То, что советуете вы это просто кэширование выходного потока.
Я же писал статью о кэшировании данных в целом, делая упор на кэширование “чистых” данных.
Поймите меня, мы спорим о разном!!! И тот и тот подход хорош. Разве, что я все-таки не согласен с тем, что кэширование должно зависеть от шаблонов. Хотя если это кэширование выходного потока, то почему бы и нет?!
Но для моего случая ваш метод не подходит. Я уже не один день пытаюсь вам это объяснить.
Все рассказывают об одном и том же, просто применительно к разным данным. Кэширование - оно и в африке кэширование. А к чему его применять зависит от ситуации.
В общем виде интерфейс выглядит так:
class Cache {
function set($id, $data, $param){}
function get($id){}
function isCached($id){}
}
Где $id - идентификатор записи кэша.
$data - данные, которые надо кэщировать.
$param - параметр, определяющий условие ревалидации кэша.
Всё. Остальное - вопрос конкретной реализации.
Ты забыл еще метод удаления/очещения кэша.
Итого:
interface Cache {
function set($id, $data, $param){}
function get($id){}
function isCached($id){}
function forceCleanup($id = ‘all’){}
}
Я так прикинул… а зачем вообще открытый метод isCached? ИМХО, это служебный private метод данного класса.
if(!isCached($myid)){
$data = $db->select("select * from data");
$cache->set($myid, $data, 36000);
}
else{
$data = $cache->get($myid);
}
Мой вариант более короткий
Хотя в нем есть один недочет =)))
Нифига себе “недочёт” :)
Да, ладно, его не сложно обойти.
А вот время “жизни” кэша все же удобнее задавать в методе load(set). Так будет более универсально, см. статью о кэшировании при помощи memcache и сразу все станет ясно.
$cache->set($myid, $data, 36000); с memcache будет довольно проблематично написать.
Ну, я тут не только время жизни имел ввиду… тут можно и посожнее условие наворотить.
Например?
Хотя нет… уже начинаю путать с кэшем на клиенте. Кроме времени жизни тут ничего не нужно.
if (!$var = $cache->load(’mega’, 10*60))
А если $var == 0 ?:) вполне корректное значение, а условие не выполнится, так-как при конвертации в bool получится false :)
правильно писать
if (false !== $var = $cache->load(’mega’, 10*60))
{
…
}
Вот оно!!!
Ents, как я вас давно ждал!!! Наконец-то у блога появился внимательный и не ленивый читатель! =) (это я без юмора, совершенно серьезно)
Совершенно, верно, в проекте так и сделано. Точнее было сделано после предыдущих замечаний. Но код решил не выкладывать, надеялся, что это сделает один из читателей - так и случилось!
admin,
я не сталкивался с необходимостью кэширования, не могли бы вы привести пример в каких случаях оно может оказаться полезным и сэкономить ресурсы? ведь обычно (особенно в современных проектах) преобладает динамическое содержимое, а не статическое.. да и статическое (тексты и все такое и так хранятся в файлах или БД, зачем же их ещё кэшировать?)
вы вот приводили пример с тегом B.
я так и не понял, вы за или против того, чтобы кэшировать его?
*сорри, забыл врубить нотифы*
Alx , иногда запросы к БД(к примеру) довольно таки ресурсоёмкая операция.
в последнее время редко вижу что бы что-то хранилось в файлах)))
+ Не весь сайт у тебя динамический, т.е. существуют блоки которые меняются или крайне редко или при определённых действиях пользователя…
просто я не представляю себе, каким должен быть запрос к бд (который к тому же возвращает статическую независимую информацию), чтобы ради него работать с файлами и медленной функцией serialize..
Ууу…
Постройте-ка мне дерево из вот-такой табличке и выведите у каждого узла количество подузлов:
tree
–
id
parent_id
name
p.s. в дереве всего 5000 элементов в 5 уровней вложенности максимум.
где это вы такие деревья растут? :)
Да где угодно.
http://www.softodrom.ru/
http://softsearch.ru/
Но это ещё так… фиговенькое дерево. Вот если взять системы документооборота - вот там уже будет реально то, что я привёл в пример.
@Alx
Если не нравится кэшировать в файлы, всегда можно кэшировать в память. =) Об этом моя вторая статья.
Вот поэтому мы и кэшируем данные (результаты вычислений так сказать), а не страницы целиком. При таком подходе и нагрузка снижается, и обновляемость данных не страдает.
Я приведу другой пример, из реальной жизни (моей). На проекте “Моя библиотека” есть рекомендательная система. Алгоритм рассказывать не буду :) Но рекомендации пользователю даются на основе 7-9 таблиц с кучей параметров. Таблицы в районе 70 000 - 100 000 записей и постоянно растут.
Если производить такие вычисления без кэширования, то придется ставить целый кластер на один проект, что гораздо дороже написания простого кэширования - и даже кэширования в файлы!
Да и при большом наплыве посетителей, без кэширования, такой сайт просто не выдержит нагрузки. :)
@Sam, если на проекте нужна частая выборка большого дерева, то его стоит построить, например, на материализованных путях.
Знаю :) Просто часто раньше приходилось работать с готовым.
Я не сомневался, что знаешь. ))))
[off]Кстати, поздравляю с первым местом в рейтинге моих комментаторов))))[/off]
Я не специально. Просто у тебя хорошие темы.
[...] своей первой статье о кэшировании, я рассказывал о кэшировании информации в файлы. Данный тип кэширования можно использовать на всех [...]
Для начла спасибо за статью, очень полезная и интересная, спасибо всем кто имел возможность комментировал, очень было интересно почитать. Я конечно далеко не такой спец как тут многие, но вопросы конечно имею.
Скажите пожалуйста, вот например рассмотрим ваш сайт, но предположим что статьи добавляются каждую мили секунду, комментируют статьи еще чаще, то как в таком случае и есть ли смысл кешировать АКТИВИСТЫ, ПОСЛЕДНИЕ ТЕМЫ и ПОСЛЕДНИЕ КОММЕНТАРИИ??
Если кешировать все это дело то актуальность и верность данных будет страдать, даже если это кеширование будет через каждые 10 минут. Если же не кешировать то при большом кол-ве посетителей эти разделы будут одним из узких мест сайта, которые создадут огромную нагрузку на сервер.
Спасибо за ответ.
Кстати, я тоже приверженец того, что бы сохранять кешь как ХТМЛ блок, и в этом я понимаю vasa_c.
Кстати, в этом случае решить проблему можно вызовом функции которая будет очишать обновленный блок в момент обновления - хотя тоже узковатое место..
Скажите, где вы видели такие проекты? Кэширование - это жизненные реалии, а вы приводите абсолютно не жизненный пример.
Хотя если такой проект существует, то кэширование хотя бы на пару секунд ему сможет помочь, но там другой подход. Да и на таких проектах упор скорее делается на распределение нагрузки, нежели на кэширование.
Такой подход точно не подойдет к описанному вами сайту (где статьи генерируют роботы, каждые доли секунды ), а вот кэширование по частям, можно будет использовать в проекте.
Ну вы сами поняли, что сказали что-то не то =)))
Большое спасибо за статью, конечно решение простое но очень эфективное как по мне, на вирт. хостах только так и кэширую :)
поддерживаю!
я как то тоже кэшировал HTML-блоки или страницы, но вот про кэширование самих данных как то и не думал даже :)
интересная мысль
@iniweb
@mex
Спасибо, за лестные отзывы. =)
Скажите, где вы видели такие проекты? Кэширование - это жизненные реалии, а вы приводите абсолютно не жизненный пример.Если ваш проект завтра превратиться в любимца миллионов людей во всем мире, у вас появится еще с десяток писателей - это не реалии???
Такой подход точно не подойдет к описанному вами сайту (где статьи генерируют роботы, каждые доли секунды ), а вот кэширование по частям, можно будет использовать в проекте.честно, не пойму.
если данные актуальны, например, каждые 5 минут, то проще сохранить блок хтмл, чем данные.
потому как за эти 5 минут, в первом случае будет грузится только код хтмл, а во втором случае производится вычисления…
Ну вы сами поняли, что сказали что-то не то =)))это не то будет во всех случаях тогда. как в первом так и во втором… вот и спрашиваю, что делать тогда :)поддерживаю!поддерживаю, тоже никогда не думал, но смысл в них, может быть только если СТРАНИХ МНОООООООООООООГО а обращаются к ним крайне редко… Я так думаю.. :) Может и ошибаюсь.я как то тоже кэшировал HTML-блоки или страницы, но вот про кэширование самих данных как то и не думал даже :)
интересная мысль
Спасибо за полезную статью, и за интереснейшее развитие темы в комментариях.
И все же пока придерживаюсь мнения господина vasa_c по поводу кэширования конечными оформленными и наполненными HTML / XML / PDF страницами.
Ведь вариантов выдачи данных кроме этих еще совсем немного (на вскидку RSS, как подвид XML + WML) и новых пока нам вроде не светит. Ну может HTML быть два вида под PDA и под нормальные браузеры (хотя это зачастую можно решить правильным написанием CSS).
А по поводу изменения и «полужирнования текста» если я залезу заливать обновленные контролеры / модель по FTP кто мне мешает руками удалить не актуальные страницы из кеша, тем более если они будут лежать в правильное иерархии, достаточно будет удалить папку, ну сгенеряться снова — не страшно имхо.
P.S. Все сказанное имхо.
P.P.S. Я бы использовал … за место … в комментариях, поле маленькое, а в стронг — многа буков ;) И еще бы навесил стандартные хот кеи: ctrl+b, ctrl+u, ctrl+i ;) Еще раз спасибо за статью. В мемориз.
Вот же так и думал что теги пропадут… :(
В общем b … /b, за место strong … /strong
@DenCh
Спасибо за высокую оценку.
На счет подхода к кэшированию - верны оба варианта: и кэширование страницы целиком (html), и кэширование “чистых” данных (массивы, объекты и т.д.).
Просто каждый стоит использовать по назначению, например, если информация на странице постоянно (очень часто) изменяется и состоит из множества хелперов нет никакого смысла кэшировать страницу целиком - т.к. очень часто придется ее пересобирать. Если же информация меняется крайне редко, то подход кэширования целиком себя оправдает.
Опять таки что подразумевать под часто, тут выше была одна «сумасшедшая» версия «бешенного сайта» с ежесекундно комментируемыми страницами :) тогда, имхо на самом деле никакое кэширование не спасет, и только расширением.
Ваш метод интересен, но при высокой скорости изменения контента, точно так же кеш буде либо быстро становиться не актуальным, либо нагрузки на кэширование буду высоки, а как выше отмечалось верно сериализация, ресурсоемкая операция.
Но повторюсь метод хорошо, особенно если на одном сайте есть множество вариантов отдачи контента, но с другой стороны PDF генерация, на лету может убить все, она по моему достаточно ресурсоемкая.
Но например для HTML + XML + WML отдачи хорошо.
По поводу “сумашедшей” версии, могу показать вам свой сайт, немного я конечно утрировал что пишут каждую секунду, но даже до 10 минут тоже считаю не верный подход. Странно, Все программисты а представить себе далеко не сложную ситуацию не можете.
Огромная разница между ежесекундным и раз в 5 - 10 минут.
При втором можно сделать кэширование на целых 5 минут, а это очень не мало при такой посещаемости.
P.S. В том то и дело что программисты, а не блондинки для которых 5 секунд или 5 минут или день — без разницы.
Это я не в сторону вас камень кида, это безотносительно. Разница есть.
Спасибо что я не блондинка. А теперь рассмотрим такую ситуацию. Пишут 1 раз в 10 минут, зато обращений к этим данным НАМНОООООГО больше. Кешировать данные или кешировать кусок кода, есть разница?!. А по поводу раз в 10 минут, это понятие не постоянное, может быть через секунду на протяжении нескольких минут, потом через десять. А ты потом объясни пользователю который написал только что сообщение почему его нету где оно должно быть. Да, есть решение, удалять кешь после определенных действий - но в случае когда сообщений будут отставлять каждую секунду… Вообщем мы тут не блондины и дальше все понятно..
Мне кажется в случае со статическим хтмл, сильно усложнять ничего не надо…
Вот мой код
$fn = "static_dir_html/static_file_name.ext";$fmt = @filemtime($fn);
if ($fmt && time()-$fmt < 60)
{
echo time()-$fmt;
include_once $fn;
}
else
{
$content = megacalculation();
echo $content;
$fhandle = fopen($fn, "w");
fwrite($fhandle, $content);
fclose($fhandle);
}
дейсвительно, если файлов больше 1000 для *ксов надо сделать еще и директории…
echo time()-$fmt; лишняя строчка, это для меня :)
function cache_html ($file_category_name, $time_format = "Ymd", $time_dif = 1){
$cache_file = 'static_html/'. $file_category_name . '.html';
if (@is_file($cache_file) && @filesize($cache_file) )
{
$valid = ( date($time_format,time()) - date($time_format,@filemtime($cache_file)) < $time_dif ) ? true : false;
}
else
{
$valid = false;
}
if ($valid )
{
@include_once($cache_file);
}
return $valid;
}
это для любителей функций, несколько модифицированый скрипт, то была одна из первых версий …
надеюсь автор замечательного блога не будет против если я здесь оставил свои наработки.
Конечно я не против, только за! )))
Маленький совет, при вставке кода пользуейтесь конструкцией: < pre >< code >…< /code >< /pre >
ок. спасибо
//в инклюд #########################################################################
function cache_html ($file_category_name, $time_format = "Ymd", $time_dif = 1)
{
$cache_file = 'static_html/'. $file_category_name . '.html';
if (@is_file($cache_file) && @filesize($cache_file) )
{
$valid = ( date($time_format,time()) - date($time_format,@filemtime($cache_file)) < $time_dif ) ? true : false;
}
else
{
$valid = false;
}
if ($valid )
{
@include_once($cache_file);
}
return $valid;
}
#########################################################################
function cache_stores ($file_category_name, $data)
{
$cache_file = 'static_html/'. $file_category_name . '.html';
if ( $data )
{
$fp = @fopen($cache_file, "w" );
@fwrite($fp, $data);
@fclose($fp);
@chmod($cache_file, 0777);
}
}
#########################################################################
function cache_clear($file_category_name)
{
$cache_file = 'static_html/'. $file_category_name . '.html';
if (@is_file($cache_file))
{
$fp = @fopen($cache_file, 'w');
@fclose($fp);
@chmod($cache_file, 0777);
}
}
//в конфиг
DEFINE ("TIME_FORMAT_DEFAULT", "YmdHi"); // проверка поминутная, YmdH - по часовая и тд.
DEFINE ("STATIC_TIME_LIVE_DEFAULT", 10); // 10 минут
//там где нужно кешировать
$file_category_name = "cache_blok_name";
if (!cache_html ($file_category_name, TIME_FORMAT_DEFAULT , STATIC_TIME_LIVE_DEFAULT))
{
$content = get_megacontent();
echo $content;
cache_stores ($file_category_name, $content);
}
буду рад если кто-то оставит свои мысли по этому поводу.
коды использовал, разультата не дало :)
А ты случаем тег PRE, не пропустил?
У меня как видишь все ОК
У меня вопрос по кешированию на примере фотогалереи.
Сразу предупрежу что я начинающий =)
Пример следущий:
Фотогалерея. Собственно происходит обработка БД со списками альбомов и фотографий.
После этого уже осуществляется вывод информационной части.
Вопрос: Хотелось бы сделать кеширование которое будет срабатывать в случае если никто не добавлял альбомов и фотографий. Если же была добавлен хоть один элемент то должно произойти кеширование.
удаляете кешь когда что-то добавляется.
функция автоматически его создаст…
можете использовать куски моих функций… и будет вам счастье
ну да удаляете кеш))) насмешил, если у тебя кеша на гб даных которые связаны а ты каждый раз когда чтото изменилось удалешь кеш) ню ню) я к тому что в голом виде вот это решает проблему кэширования данных на очень простом упрощенном уровне когда данные не связаны, не раскрыт смысл логики более высокого уровня которая в этом случае будет удалять только то что зависит от изменившихся данных
а твои “куски” кода вообще написаны на уровне Я ТОЛЬКО ЧТО НАУЧИЛСЯ КОДИТЬ НА ПХП, и второе ГЛАВНОЕ ШОБ РАБОТАЛО
Дмитрий:
Я думаю целью этой статьи автор предполагал не показать алгоритмы решения тех или иных задач, а просто показать людям как выполняется функция кеширования.
хм поэтому поводу итак хлама довольно, я думаю кроме этого хотел продемонстрировать как правильно эта задача решается с применением ООП для PHP5, но даже этого вобщемто достаточно, просто я ожидал более широкого взгляда под общим заголовком PHP-кеширование или это для заполнения поисковой ниши? заголовк такой)))
Не исключено. Не буду спорить, но статья мне понравилась, все довольно просто и доступно показано.
Дмитрий, никто не говорит удалять 1гбайты кода, удаляется только та часть что отвечает за определенный блок.
Спасибо что сделали вывод по моим кускам кода, мне кажется было бы лучше для всех нас или как минимум для меня что бы вы показали как из этого сделать лучше.
И еще раз, спасибо за кртиику… :)
@Дмитрий
Я долго ждал этого момента! И вот свершилось - мой блог, наконец-то, посетил настоящий знаток программирования и монстр объектного проектирования! Ура!
И вот я и все мои читатели ждем с нетерпением, когда же великий Дмитрий, покажет нам мастер-класс…
Хотелось бы услышать насколько такое кеширование еффективно…
Эффективно )))
Проверено на реальных проектах
[...] Скажи кэшированию… иногда [...]
Опередил меня Дмитрий).
Собираю простенькую cms. Решил включить туда кеширование. В связи с тем что задачи для кеширования будут разными, будут употребленны 2 метода кеширования.
1. Кеширвоание всей страницы, или блока html.
2. Кеширование ответов BD или еще каких ресурсоемких функций.
Сейчас как раз думаю, и ищю ответы как обзывать файлы, чтобы потом можно было не удалять весь кэш, а удалять только тот который затронут изменением.
Все что приходит в голову,
/cashe/ папка с кэшем.
/cashe/modul-name/ папка с кешем для конкретного модуля.
Теперь о имени файла.
Если сохраняю страницу, то идентификатором будет md5(’modul-name’ . ‘Гет переменные которые влияют на содержимое страницы. Например Номер страницы в новостях.’).’.html’;
если сохранять данные, то md5(’SQL_QUERY’).’.php’ или md5(’function_name’.explode($parametry_func)).’.php’
Ничего нового не сказал вроде бы). Я так уже делал) Но совсем недавно форматнул диск, бекап наработак не сделал. В итоге теперь я гол как сакол) Хочу все начать сначала, структурировать, ну и сделать красиво
верно должно быть так, иначе кэш никогда не будет создан
if (false === $var = $cache->load(’mega’, 10*60)){
…
}
@DeadLy,
согласен )
замечание - правильный интерфейс, но не правильные места у переменных имхо.
проще для запоминания и логичности - так
парсер код сожрал :(
епт опять … как код запихнуть? )))))))))))))))))
Читал диалог с товарищем vasa_c. Пил чай с булочкой и с упоением вчитывался в вашу переписку :) Админу крайняя степень уважения за проявленную выдержку! Видит Бог, я бы не выдержал)
@Oleg,
спасибо!
Мне кажется, выдержка - это одно из обязательный качеств разработчика ) Заказчики и не такие бывают ;) А vasa_c все таки “коллега по цеху” )
З.Ы.: если не узнали, то admin === Larin
Да, само собой, но всему есть предел :) И мой предел товарищ vasa_c нашел бы очень быстро. Я, наверное, очень придирчив, потому не сдержался бы, если бы человек спорил на какую-то тему, не имея достаточного представления о ней. Это я к тому, что vasa_c, судя по всему, не совсем понимает для чего нужно кэширование и как его использовать.
Ну да ладно, забавно было почитать :)