кеширование Как создать свой сайт > Вебмастеру > Создание своего сайта > Скажи кешированию… иногда :)

Скажи кешированию… иногда :)

Вся его жизнь была долгим бунтом против собственной малозначительности.
«Корни неба», Роман Гари.
16 октября 2007

    Когда я писал статью о 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 (false === $var = $cache->load(’mega’, 10*60)) {
	$var = megaCalculation();
	$cache->save($var, 'mega');
}
?>

    Вот и всё. Кеширование — это просто :)

    Внимательный читатель спросит: «А зачем было делать класс Cache?». Всё просто. Кеширование бывает не только на файлах. И в этом классе мы описываем обязательные методы для всех производных классов.

    Можно ещё кешировать при помощи MemCache, баз данных (например, Berkeley DB) и т. д. Но это уже тема для следующих статей :)

Автор: Анатолий Ларин.

 

 

Комментарии:

SHAman
Интересно, спасибо. Только код читать неудобно: overflow: hidden мешает…

larin
SHAman, пожалуйста. Я отредактировал – сделал переносы. Теперь все должно быть нормально.

SHAman
Не, не нормально… Может, сделать overflow: auto? Тогда скрольчики хоть появятся, а то из исходника читать неудобно. Конечно, можно из RSS... но все равно не айс:) (IE7, 1024x768)

larin
Спасибо, за замечание. У меня монитор широкоформатный (1280х800) поэтому и неудобств не видел…

Valentin Gernovich
Я как очень внимательный читатель спрашиваю, а может данный класс нужно было сделать синглетоном? Врядли в проекте необходимо куча объектов класса CacheFile.

larin
Valentin Gernovich, согласен. =)
В рабочем примере так и есть. Но здесь я решил упростить ))) Наверное зря. Переделаю.

Patrick
Valentin Gernovich, зачем тут Singleton ? ихмо Registry рулит)))
admin,
1. тему с константаки не осилил, особенно с DIRSEP.
2. Вообщето использовать на прямую CacheFile плохо… допустим есть необходимость перейи на Memcache. как быстро ты сделаешь?
3. По больному счёту в классе Cache болжно быть 3 метода(load,save,delete). Покажи пример метода pathCache или nameCache для Memcache…

larin
Patrick,
мало букв не осилил? Или что? DIRSEP, это так сказать псевдоним системной константы DIRECTORY_SEPARATOR. Просто системное название довольно длинное. =)
Второе, Патрик, пример учебный так сказать. Этот пример создан для того, чтоб показать, что кэширование это просто. [Ctrl+H :)]
На третий вопрос отвечу позже. В статье по MemCache ;)
З.Ы. По поводу Singleton… При наличии реестра, Singleton не отменяется. ИМХО, лучше всего в данном случает использовать и то, и то. Registry – для удобства доступа, Singleton – для защиты “от дураков”.

Patrick
мало букв не осилил? Или что? DIRSEP, это так сказать псевдоним системной константы DIRECTORY_SEPARATOR. Просто системное название довольно длинное. =)
Зачем только?
З.Ы. По поводу Singleton… При наличии реестра, Singleton не отменяется. ИМХО, лучше всего в данном случает использовать и то, и то. Registry – для удобства доступа, Singleton – для защиты “от дураков”.
Баян! Ты правда так думаешь?

larin
Patrick, ну что мне тебе на это сказать?
Да, я действительно так думаю, иначе не написал бы этого.

Patrick
Ну тогда тебе подойдёт:
Использование одиночек и тестирование. Использование паттерна Registry как альтернативы одиночкам
Инверсия зависимостей при проектировании Объектно-Ориентированных систем
Управление зависимостями в PHP-коде
ЗЫ последнее ты должен был слышать на конфе)))

larin
Patrick, спасибо за ссылки. Да, признаю – переборщил немного =)
А линки действительно хорошие… сижу – читаю.

Valentin Gernovich
Постепенно разговор переходит из темы конкретного примера, в тему ООП проектирования и применения патернов :)
Пока лучше не отвлекайся на идеальное решение, пиши про кэширование в память, в БД, и еще куда только возможно. Сосредоточься на алгоритмах. А потом объедини в один пакет, где все будет реализовано по грамотному.
PS Я DIRECTORY_SEPARATOR в своих проектах переопределяю в констатну DS, так еще лаконичнее и удобочитаемо.

cyberfox
Спасибо, но я пока что в кэшировании не нуждался. А так в мемориз :)

larin
cyberfox, на здоровье! Скоро будет продолжение =)

LARIN » Архив блога » Скажи кэшированию… иногда. Часть 2: Memcache
[...] своей первой статье о кэшировании, я рассказывал о кэшировании информации в файлы. Данный тип кэширования можно использовать на всех [...]

vasa_c
День добрый.
Почему не HTML? Что за блоки?
Что за вечное сияние чистых данных в отрыве от HTML?

Patrick
vasa_c
Что за блоки?
Как правило web-страница состоит из блоков….
Что за вечное сияние чистых данных в отрыве от HTML?
Кэш не должен влиять на View. Ему должно быть пофиг какой шаблон этими данными воспользуется!

Patrick
ИМХО использовать “кэшированный” HTML(т.е. не чистые данные), следует в случае если в последующем будет использоваться SSI

vasa_c
>Как правило web-страница состоит из блоков….
Ага, из HTML-блоков )
>Кэш не должен влиять на View.
View, это хорошо, но браузеры пока не знакомы с паттернами, а знакомы только с HTML. И только его можно выдавать (если, конечно, не хотите нагрузить клиента xslt-преобразованием).
Все эти данные нужно пропускать через шаблоны, что будет есть лишнее время, а смысл кеширования тогда в чем?

vasa_c
Хотя, ладно, может быть я и загнул. Кешировать можно не только HTML, но и просто результаты вычислений.
Но по большому счету в классе увидел только сохранение/получение переменных, что само по себе хорошо, но еще не полноценный кеш.
По хорошому, кеш получив запрос данных, должен проверить их наличие и актуальности и если надо самостоятельно провести вычисление и сохранение данных.
Даже функция set здесь по большому счету не нужна.

larin
vasa_c, я рад, что не придется переубеждать, что кэшировать HTML это плохо, если проект часто меняет и содержимое и возможно оформление. Что сейчас для всяких стартапов, занятие актуальное.
На счет того, что страница состоит из HTML-блоков, это так, но в определенной абстракции. И эта абстракция не для программистов, а для кодеров или верстальщиков. =)
Странно, что вы не заметили, но кэш получив запрос здесь проверяет наличие данных и их валидность (правда только по сроку хранения). ИМХО, валидация содержания кэша убъет его скорость и универсальность полностью, так что пока от такого изощрения, я воздержусь. =)))
А вот ваша фраза: и если надо самостоятельно провести вычисление и сохранение данных меня просто убила! Ага! =)
Кэш должен только кэшировать и все. Иначе гибкость вашей системы летит ко всем чертям. У вас появится куча зависимостей и т.д. и скелет системы закостенеет и … она вымрет, как мамонты. :)
З.Ы. Спасибо, Патрику, за ответу на вопросы пока я был вдали от компа. ))))

larin
Да, совсем забыл vasa_c почитайте мою следующую статью о кэшировании, может станет более понятной моя идея.

Patrick
Кэш должен кэшировать!!!
Модель извлекать данные!!!
Кэш и Модель должны пересекаться в контроллере!!!
ИМХО!!!

larin
To: Patrick
Ого! Прям Маяковский!
И прАльно!!!
Землю крестьянам! Заводы рабочим!!!
И чтоб они пересекались только в баре!

vasa_c
>На счет того, что страница состоит из HTML-блоков, это так, но в определенной абстракции.
Это не абстракция, это суровая реальность. Какой бы движок не был супер-пупер абстрактный и невооброзимо паттерный, на выходе всё равно должен быть банальный html.
>валидация содержания кэша убъет его скорость и универсальность полностью
Под валидацией я имел ввиду всё ту же проверку времени. Только со стороны самого кеша.
Универсальность это хорошо, но здесь эта универсальность дошла до того, что это уже и не совсем кеш, а просто хранение переменных (ну еще иногда с проверкой по времени).
>Кэш должен только кэшировать и все.
Да. Но здесь он не кеширует. Здесь кеширует внешний код, которой просто использует данную либу для сохранения данных

vasa_c
ЗЫ. Вообще в абстрактных системах, которые решают абстрактные задачи на абстрактно-чистых данных, кеша быть не должно.
Так как он решает проблемы только грубого реального мира — экономию реальных ограниченных ресурсов.
И в этом грубом мире браузеры показывают только html. И получение html с помощью преобразования данных на основе шаблона так же трудоемкая задача.
Почему он не может кешироваться?
Причем тут модели, разные шаблоны? Это совершенно из другой оперы.

larin
vasa_c, супер!
Может поделитесь примером кода правильного кэша?
To: all Может, кто-нить ответит господину vasa_c, а то у меня аж дар речи пропал )))

vasa_c
Ладно, не буду утруждать вас своими глупыми речами.
Всего хорошего.

larin
vasa_c, не нужно обижаться. Простите, если задел (у меня бывает :) )
Вы лучше поделитесь, примерами хорошего кэширования. Это будет интересно всем.

vasa_c
А я не обижаюсь. Я от рождения не обидчивый, а долгое пребывание на форумах окончательно притупило это чувство :-D.
Я не пришел делиться примером правильного кеша. И не собирался говорить “вот мой правильный кеш, а ваш — д.мо”.
Я просто задал несколько вопросов, чтобы может быть кто-нибудь над чем-нибудь задумался и ничего больше.
А то, что кто-нибудь мне может ответить, пока у Вас пропал дар речи, я, скорее всего, уже слышал от других, читал в книгах и реализовывал сам :)

larin
vasa_c, я рад, что вы по прежнему с нами =)
И в продолжении:
>>>>На счет того, что страница состоит из HTML-блоков, это так, но в определенной абстракции.
>>Это не абстракция, это суровая реальность. Какой бы движок не был супер-пупер абстрактный и невооброзимо паттерный, на выходе всё равно должен быть банальный html.
Вы меня все же не поняли. Что такое абстракция?
>>Под валидацией я имел ввиду всё ту же проверку времени. Только со стороны самого кеша.
Универсальность это хорошо, но здесь эта универсальность дошла до того, что это уже и не совсем кеш, а просто хранение переменных (ну еще иногда с проверкой по времени).
А у меня проверкой времени разве не кэш занимается?
>>Да. Но здесь он не кеширует. Здесь кеширует внешний код, которой просто использует данную либу для сохранения данных
Покажите мне другой подход, на примере.

vasa_c
>Вы меня все же не поняли. Что такое абстракция?
Фиг с ней с абстракцией.
Весь этот флуд я развел только исходя из вашей фразы “мы будем кэшировать только чистые данные, т.е. никакого HTML”. Вот и не понятно, почему HTML считается грязными данными.
>А у меня проверкой времени разве не кэш занимается?
Не совсем. Вычислением времени устаревания и обработкой ситуации с устаревшими данными занимается внешний сценарий.
>Покажите мне другой подход, на примере.
Давайте с HTML пока закончим )

larin
>>Вот и не понятно, почему HTML считается грязными данными.
Из того, что я назвал, данные без HTML чистыми, вовсе не следует, что данные с HTML – это грязные данные. =) Нет, это данные С ОФОРМЛЕНИЕМ. А оно как известно может меняться. Так, что же если мы сделали, где-то жирное выделение, нам весь кэш чистить? А он на некоторых проектах живет ОЧЕНЬ долго. И его новый пересчет может обернуться плохо.
А все из-за тега B. =))
>>Не совсем. Вычислением времени устаревания и обработкой ситуации с устаревшими данными занимается внешний сценарий.
Как это?! вычислением занимается кэш, а вот запуском этих вычислений занимается внешняя программа.

vasa_c
>А оно как известно может меняться
Меняться может всё )
Вот есть у нас система, которая формирует ответ на запрос. Формирует его в несколько этапов. Последний этап – заполнение шаблона данными и получение html.
Собственно, на каждом этапе производятся какие-то вычисления, которые потребляют ресурсы.
Дабы, снизить нагрузку результаты мы кешируем.
Чем последний этап хуже других? Или формирование html легкая задача на сложных шаблонах? Почему не кешировать эти результаты наравне с результатами всех вышестоящих уровней?
Пересчет не должен оборачиваться плохо. Он должен пересчитывать только то, что нужно и только тогда когда нужно.
>вычислением занимается кэш
Вычисление, это формирование тех самых данных, которые храним в кеше.
Именно внешний код выполняет свои мегакулькуляции и вручную их сохраняет в кеше.
Получив из кеша (getValue) false, именно внешний скрипт должен перемегакуалькулировать всё по новой и опять вручную сохранить в кеше.
Кстати, а почему false? Разве false не может быть равноправным данным? Имхо, лучше исключения задействовать.

larin
vasa_c, вы продолжаете гнуть свою линию.
НО, мы с вами говорим о РАЗНЫХ ТИПАХ, кэширования! Оба они хороши, но применяются в различных ситуациях, то кэширование о котором рассказываете вы – это кэширование вывода. Оно менее гибко, но более быстро в отдаче, т.к. отдается уже сформированная страница.
Еще раз повторюсь, мы спорим о разных вещах. :) И обе эти вещи хороши, но они РАЗНЫЕ.
А вот на счет false – вы правы ))) Хотя как знать… надо подумать над этим.
З.Ы. Что-то нашу беседу все игнорируют (

vasa_c
А я как раз пытаюсь понять, почему именно они разные.
Я не имею ввиду кешировать целые страницы в html-файлы.
А именно кешировать отдельные html-блоки. Причем наравне с кешированием данных на всех других уровнях системы.

larin
Можно кэшировать и HTML-блоки, но мне такой подход не нравиться.
Так, например, на сайте некоторый кэш может жить по несколько недель… но при этом, сайт активно развивается и устраивает различные промо-акции и т.д. Некоторые промо-акции требуют частичного изменения дизайна сайта, например, добавление новогодней тематики в канун новогодних праздников. Т.о. велика вероятность, что для данного изменения нам потребуется сбросить кэш, а это лишние тормоза в период промо-акции, что естественно не допустимо.

vasa_c
Так зачем сбрасывать кеш? :)
Кеш для страниц будет просто устаревшим. При запросе он переформируется.
При Вашей же нелюбви к кешированию HTML это формирование будет происходить при каждом запросе.

larin
>>Кеш для страниц будет просто устаревшим.
Это в честь чего???
Например, мы создали кэш сегодня. С временем жизни 2 недели. Через неделю мы изменили некое оформление, но т.к. кэш у нас валиден еще неделю, нам показывается старое оформление. И что мы делаем? Правильно :), сбрасываем кэш. Ч.Т.Д.
У меня нет не любви к кэшированию HTML-кода, когда это рентабельно, я это делаю. Просто в данной статье я взял, на основу те системы, где кэширование HTML-кода не рентабельно. А вы решили будто я противник кэширования HTML вообще ))))

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

larin
Вы упорно не хотите меня понимать. Вы хоть раз сталкивались с управлением и сбросом кэша на большом проекте на практике?

vasa_c
Да, сталкивался.
Я упорно понимаю Вас с самого начала.
На кова чорта, прошу прощения, его сбрасывать, вместо того, чтобы пометить неактуальным?

larin
vasa_c, скажите, а как вы собираетесь помечать его не актуальным? При модификации только файлов шаблонов…

vasa_c
А как происходит модификация файлов шаблонов?

larin
А как происходит модификация файлов шаблонов?
Как, как? В любом редакторе, с последующей заливкой на сервер. Это при условии, что у нас нет админ интерфейса по управлению шаблонами.

vasa_c
а как вы собираетесь помечать его не актуальным?
В случае с
В любом редакторе, с последующей заливкой на сервер
банально смотреть время модификации файла
при
админ интерфейсе по управлению шаблонами
возложить нужные действия на этот интерфейс

larin
банально смотреть время модификации файла
Вы чего??? Вы предлагаете, чтоб кэширование еще и за шаблонами следило?

vasa_c
Да.
Проверять данные на актуальность, это прямая обязанность кеширования.

Patrick
:) Шаблоны это не данные!
Во всторых почему я считаю что данные с HTML это “грязные” данные, да только по тому что помимо HTML есть разного рода XML и т.д.

larin
Да.
Проверять данные на актуальность, это прямая обязанность кеширования.
Но как уже было сказано – ШАБЛОНЫ ЭТО НЕ ДАННЫЕ!. =)))
И как сказал, Патрик, а что вы будете делать если несклько страниц на сайте нужно будет представить еще и в PDF?
Шаблоны – это всего лишь вариант представления данных!
Но это не данные!

vasa_c
Шаблоны не данные. А вот итоговый HTML, это данные. Данные, получающиеся, преобразованием шаблона на основании других входных данных.
Ресурсоёмкого преобразования.
Почему не кешировать эти результаты?
PDF, XML? И что, чем они мешают? Если они так же генерируются на основании каких-то шаблонов, то их тоже кешировать не помешает.
Кешируются не данные. Кешируются результаты.

larin
vasa_c, вы не пробиваемы.
Кешируются не данные. Кешируются результаты.
С этим я согласен, но результаты бывают разные.
Но вот когда вы сказали, что кэширование должно следить за состоянием шаблонов – это уже слишком. Не считаете ли вы, что на больших сайтах шаблонов может быть просто гигантское число, особенно когда на сайте предусмотрено несколько тем?
И ваше слежение за шаблонами будет очень ресурсоемким процессом. Или вы и результат слежения будете кэшировать? =)

vasa_c
Какое слежение за шаблонами?
Шаблон это файл на диске.
Он выбирается по каким-то механизмам не относящихся к кешированию.
Потом получаем операцию
+=
вот на этом этапе нужно решит, выполнять её или взять результат из кеша. Если в кеше есть, то нужно проверить актуальность. Проверяется просто – сравнением времен генерации кеша и последней модификации файла.

vasa_c
strip_tag() ? :)
Я имел в виду
“потом получаем операцию”:
[выбранный шаблон] + [входные данные] = [результирующий html]

larin
vasa_c
Все же это уменьшает универсальность данного класса. То, что советуете вы это просто кэширование выходного потока.
Я же писал статью о кэшировании данных в целом, делая упор на кэширование “чистых” данных.
Поймите меня, мы спорим о разном!!! И тот и тот подход хорош. Разве, что я все-таки не согласен с тем, что кэширование должно зависеть от шаблонов. Хотя если это кэширование выходного потока, то почему бы и нет?!
Но для моего случая ваш метод не подходит. Я уже не один день пытаюсь вам это объяснить.

Sam
Все рассказывают об одном и том же, просто применительно к разным данным. Кэширование – оно и в африке кэширование. А к чему его применять зависит от ситуации.
В общем виде интерфейс выглядит так:

class Cache {
function set($id, $data, $param){}
function get($id){}
function isCached($id){}
}
Где $id – идентификатор записи кэша.
$data – данные, которые надо кэщировать.
$param – параметр, определяющий условие ревалидации кэша.
Всё. Остальное – вопрос конкретной реализации.

larin
Sam:

class Cache {
function set($id, $data, $param){}
function get($id){}
function isCached($id){}
}
Ты забыл еще метод удаления/очещения кэша.

Sam
Итого:

interface Cache {
function set($id, $data, $param){}
function get($id){}
function isCached($id){}
function forceCleanup($id = ‘all’){}
}

larin
Я так прикинул… а зачем вообще открытый метод isCached? ИМХО, это служебный private метод данного класса.

Sam

if(!isCached($myid)){
$data = $db->select("select * from data");
$cache->set($myid, $data, 36000);
}
else{
$data = $cache->get($myid);
}

larin
Мой вариант более короткий

if (!$var = $cache->load('mega', 10*60)) {
}
Хотя в нем есть один недочет =)))

Sam
Нифига себе “недочёт” :)

larin
Да, ладно, его не сложно обойти.
А вот время “жизни” кэша все же удобнее задавать в методе load(set). Так будет более универсально, см. статью о кэшировании при помощи memcache и сразу все станет ясно.
$cache->set($myid, $data, 36000); с memcache будет довольно проблематично написать.

Sam
Ну, я тут не только время жизни имел ввиду… тут можно и посожнее условие наворотить.

larin
Sam:
Ну, я тут не только время жизни имел ввиду… тут можно и посожнее условие наворотить.
Например?

Sam
Хотя нет… уже начинаю путать с кэшем на клиенте. Кроме времени жизни тут ничего не нужно.

>Ents
if (!$var = $cache->load(‘mega’, 10*60))
А если $var == 0 ?:) вполне корректное значение, а условие не выполнится, так-как при конвертации в bool получится false :)
правильно писать
if (false !== $var = $cache->load(‘mega’, 10*60))
{

}

larin
Вот оно!!!
Ents, как я вас давно ждал!!! Наконец-то у блога появился внимательный и не ленивый читатель! =) (это я без юмора, совершенно серьезно)
Совершенно, верно, в проекте так и сделано. Точнее было сделано после предыдущих замечаний. Но код решил не выкладывать, надеялся, что это сделает один из читателей – так и случилось!

Alx
admin,
я не сталкивался с необходимостью кэширования, не могли бы вы привести пример в каких случаях оно может оказаться полезным и сэкономить ресурсы? ведь обычно (особенно в современных проектах) преобладает динамическое содержимое, а не статическое.. да и статическое (тексты и все такое и так хранятся в файлах или БД, зачем же их ещё кэшировать?)
вы вот приводили пример с тегом B.
я так и не понял, вы за или против того, чтобы кэшировать его?

Alx
*сорри, забыл врубить нотифы*

Andrey
Alx , иногда запросы к БД(к примеру) довольно таки ресурсоёмкая операция.
да и статическое (тексты и все такое и так хранятся в файлах или БД, зачем же их ещё кэшировать?)
в последнее время редко вижу что бы что-то хранилось в файлах)))
+ Не весь сайт у тебя динамический, т.е. существуют блоки которые меняются или крайне редко или при определённых действиях пользователя…

Alx
просто я не представляю себе, каким должен быть запрос к бд (который к тому же возвращает статическую независимую информацию), чтобы ради него работать с файлами и медленной функцией serialize..

Sam
Ууу…
Постройте-ка мне дерево из вот-такой табличке и выведите у каждого узла количество подузлов:
tree

id
parent_id
name
p.s. в дереве всего 5000 элементов в 5 уровней вложенности максимум.

Alx
где это вы такие деревья растут? :)

Sam
Да где угодно.
***
***
Но это ещё так… фиговенькое дерево. Вот если взять системы документооборота – вот там уже будет реально то, что я привёл в пример.

larin
@Alx
Если не нравится кэшировать в файлы, всегда можно кэшировать в память. =) Об этом моя вторая статья.
Alx
я не сталкивался с необходимостью кэширования, не могли бы вы привести пример в каких случаях оно может оказаться полезным и сэкономить ресурсы? ведь обычно (особенно в современных проектах) преобладает динамическое содержимое, а не статическое..
Вот поэтому мы и кэшируем данные (результаты вычислений так сказать), а не страницы целиком. При таком подходе и нагрузка снижается, и обновляемость данных не страдает.
Я приведу другой пример, из реальной жизни (моей). На проекте “Моя библиотека” есть рекомендательная система. Алгоритм рассказывать не буду :) Но рекомендации пользователю даются на основе 7-9 таблиц с кучей параметров. Таблицы в районе 70 000 – 100 000 записей и постоянно растут.
Если производить такие вычисления без кэширования, то придется ставить целый кластер на один проект, что гораздо дороже написания простого кэширования – и даже кэширования в файлы!
Да и при большом наплыве посетителей, без кэширования, такой сайт просто не выдержит нагрузки. :)
@Sam, если на проекте нужна частая выборка большого дерева, то его стоит построить, например, на материализованных путях.

Sam
Знаю :) Просто часто раньше приходилось работать с готовым.

larin
Знаю :) Просто часто раньше приходилось работать с готовым.
Я не сомневался, что знаешь. ))))
[off]Кстати, поздравляю с первым местом в рейтинге моих комментаторов))))[/off]

Sam
Я не специально. Просто у тебя хорошие темы.

Скажи кэшированию… иногда. Часть 2: Memcache – IB Blog – Статьи по дизайну, программированию, оптимизации и раскрутке сайта
[...] своей первой статье о кэшировании, я рассказывал о кэшировании информации в файлы. Данный тип кэширования можно использовать на всех [...]

M!racle
Для начла спасибо за статью, очень полезная и интересная, спасибо всем кто имел возможность комментировал, очень было интересно почитать. Я конечно далеко не такой спец как тут многие, но вопросы конечно имею.
Скажите пожалуйста, вот например рассмотрим ваш сайт, но предположим что статьи добавляются каждую мили секунду, комментируют статьи еще чаще, то как в таком случае и есть ли смысл кешировать АКТИВИСТЫ, ПОСЛЕДНИЕ ТЕМЫ и ПОСЛЕДНИЕ КОММЕНТАРИИ??
Если кешировать все это дело то актуальность и верность данных будет страдать, даже если это кеширование будет через каждые 10 минут. Если же не кешировать то при большом кол-ве посетителей эти разделы будут одним из узких мест сайта, которые создадут огромную нагрузку на сервер.
Спасибо за ответ.
Кстати, я тоже приверженец того, что бы сохранять кешь как ХТМЛ блок, и в этом я понимаю vasa_c.
Кстати, в этом случае решить проблему можно вызовом функции которая будет очишать обновленный блок в момент обновления – хотя тоже узковатое место..

larin
Скажите пожалуйста, вот например рассмотрим ваш сайт, но предположим что статьи добавляются каждую мили секунду, комментируют статьи еще чаще, то как в таком случае и есть ли смысл кешировать АКТИВИСТЫ, ПОСЛЕДНИЕ ТЕМЫ и ПОСЛЕДНИЕ КОММЕНТАРИИ??
Скажите, где вы видели такие проекты? Кэширование – это жизненные реалии, а вы приводите абсолютно не жизненный пример.
Хотя если такой проект существует, то кэширование хотя бы на пару секунд ему сможет помочь, но там другой подход. Да и на таких проектах упор скорее делается на распределение нагрузки, нежели на кэширование.
Кстати, я тоже приверженец того, что бы сохранять кешь как ХТМЛ блок, и в этом я понимаю vasa_c.
Такой подход точно не подойдет к описанному вами сайту (где статьи генерируют роботы, каждые доли секунды), а вот кэширование по частям, можно будет использовать в проекте.
Кстати, в этом случае решить проблему можно вызовом функции которая будет очишать обновленный блок в момент обновления – хотя тоже узковатое место..
Ну вы сами поняли, что сказали что-то не то =)))

iniweb
Большое спасибо за статью, конечно решение простое но очень эфективное как по мне, на вирт. хостах только так и кэширую :)

mex
поддерживаю!
я как то тоже кэшировал HTML-блоки или страницы, но вот про кэширование самих данных как то и не думал даже :)
интересная мысль

larin
@iniweb
@mex
Спасибо, за лестные отзывы. =)

M!racle
Скажите, где вы видели такие проекты? Кэширование - это жизненные реалии, а вы приводите абсолютно не жизненный пример.
Если ваш проект завтра превратиться в любимца миллионов людей во всем мире, у вас появится еще с десяток писателей – это не реалии???
Такой подход точно не подойдет к описанному вами сайту (где статьи генерируют роботы, каждые доли секунды ), а вот кэширование по частям, можно будет использовать в проекте.
честно, не пойму.
если данные актуальны, например, каждые 5 минут, то проще сохранить блок хтмл, чем данные.
потому как за эти 5 минут, в первом случае будет грузится только код хтмл, а во втором случае производится вычисления…
Ну вы сами поняли, что сказали что-то не то =))) это не то будет во всех случаях тогда. как в первом так и во втором… вот и спрашиваю, что делать тогда :)
поддерживаю!
я как то тоже кэшировал HTML-блоки или страницы, но вот про кэширование самих данных как то и не думал даже :)
интересная мысль поддерживаю, тоже никогда не думал, но смысл в них, может быть только если СТРАНИХ МНОООООООООООООГО а обращаются к ним крайне редко… Я так думаю.. :) Может и ошибаюсь.

DenCh
Спасибо за полезную статью, и за интереснейшее развитие темы в комментариях.
И все же пока придерживаюсь мнения господина vasa_c по поводу кэширования конечными оформленными и наполненными HTML / XML / PDF страницами.
Ведь вариантов выдачи данных кроме этих еще совсем немного (на вскидку RSS, как подвид XML + WML) и новых пока нам вроде не светит. Ну может HTML быть два вида под PDA и под нормальные браузеры (хотя это зачастую можно решить правильным написанием CSS).
А по поводу изменения и «полужирнования текста» если я залезу заливать обновленные контролеры / модель по FTP кто мне мешает руками удалить не актуальные страницы из кеша, тем более если они будут лежать в правильное иерархии, достаточно будет удалить папку, ну сгенеряться снова — не страшно имхо.
P.S. Все сказанное имхо.
P.P.S. Я бы использовал … за место … в комментариях, поле маленькое, а в стронг — многа буков ;) И еще бы навесил стандартные хот кеи: ctrl+b, ctrl+u, ctrl+i ;) Еще раз спасибо за статью. В мемориз.

DenCh
Вот же так и думал что теги пропадут… :(
В общем b … /b, за место strong … /strong

larin
@DenCh
Спасибо за высокую оценку.
На счет подхода к кэшированию – верны оба варианта: и кэширование страницы целиком (html), и кэширование “чистых” данных (массивы, объекты и т.д.).
Просто каждый стоит использовать по назначению, например, если информация на странице постоянно (очень часто) изменяется и состоит из множества хелперов нет никакого смысла кэшировать страницу целиком – т.к. очень часто придется ее пересобирать. Если же информация меняется крайне редко, то подход кэширования целиком себя оправдает.

DenCh
Опять таки что подразумевать под часто, тут выше была одна «сумасшедшая» версия «бешенного сайта» с ежесекундно комментируемыми страницами :) тогда, имхо на самом деле никакое кэширование не спасет, и только расширением.
Ваш метод интересен, но при высокой скорости изменения контента, точно так же кеш буде либо быстро становиться не актуальным, либо нагрузки на кэширование буду высоки, а как выше отмечалось верно сериализация, ресурсоемкая операция.
Но повторюсь метод хорошо, особенно если на одном сайте есть множество вариантов отдачи контента, но с другой стороны PDF генерация, на лету может убить все, она по моему достаточно ресурсоемкая.
Но например для HTML + XML + WML отдачи хорошо.

M!racle
По поводу “сумашедшей” версии, могу показать вам свой сайт, немного я конечно утрировал что пишут каждую секунду, но даже до 10 минут тоже считаю не верный подход. Странно, Все программисты а представить себе далеко не сложную ситуацию не можете.

DenCh
Огромная разница между ежесекундным и раз в 5 – 10 минут.
При втором можно сделать кэширование на целых 5 минут, а это очень не мало при такой посещаемости.
P.S. В том то и дело что программисты, а не блондинки для которых 5 секунд или 5 минут или день — без разницы.
Это я не в сторону вас камень кида, это безотносительно. Разница есть.

M!racle
Спасибо что я не блондинка. А теперь рассмотрим такую ситуацию. Пишут 1 раз в 10 минут, зато обращений к этим данным НАМНОООООГО больше. Кешировать данные или кешировать кусок кода, есть разница?!. А по поводу раз в 10 минут, это понятие не постоянное, может быть через секунду на протяжении нескольких минут, потом через десять. А ты потом объясни пользователю который написал только что сообщение почему его нету где оно должно быть. Да, есть решение, удалять кешь после определенных действий – но в случае когда сообщений будут отставлять каждую секунду… Вообщем мы тут не блондины и дальше все понятно..

M!racle
Мне кажется в случае со статическим хтмл, сильно усложнять ничего не надо…
Вот мой код

$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 для *ксов надо сделать еще и директории…

M!racle
echo time()-$fmt; лишняя строчка, это для меня :)

M!racle

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;
}
это для любителей функций, несколько модифицированый скрипт, то была одна из первых версий …
надеюсь автор замечательного блога не будет против если я здесь оставил свои наработки.

larin
надеюсь автор замечательного блога не будет против если я здесь оставил свои наработки.
Конечно я не против, только за! )))
Маленький совет, при вставке кода пользуейтесь конструкцией: < pre >< code >…< /code >< /pre >

M!racle
ок. спасибо

//в инклюд #########################################################################
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);
}
буду рад если кто-то оставит свои мысли по этому поводу.

M!racle
коды использовал, разультата не дало :)

larin
А ты случаем тег PRE, не пропустил?

$testClass = new TestClass();
У меня как видишь все ОК

Likos
У меня вопрос по кешированию на примере фотогалереи.
Сразу предупрежу что я начинающий =)
Пример следущий:
Фотогалерея. Собственно происходит обработка БД со списками альбомов и фотографий.
После этого уже осуществляется вывод информационной части.
Вопрос: Хотелось бы сделать кеширование которое будет срабатывать в случае если никто не добавлял альбомов и фотографий. Если же была добавлен хоть один элемент то должно произойти кеширование.

M!racle
удаляете кешь когда что-то добавляется.
функция автоматически его создаст…
можете использовать куски моих функций… и будет вам счастье

Дмитрий
ну да удаляете кеш))) насмешил, если у тебя кеша на гб даных которые связаны а ты каждый раз когда чтото изменилось удалешь кеш) ню ню) я к тому что в голом виде вот это решает проблему кэширования данных на очень простом упрощенном уровне когда данные не связаны, не раскрыт смысл логики более высокого уровня которая в этом случае будет удалять только то что зависит от изменившихся данных

Дмитрий
а твои “куски” кода вообще написаны на уровне Я ТОЛЬКО ЧТО НАУЧИЛСЯ КОДИТЬ НА ПХП, и второе ГЛАВНОЕ ШОБ РАБОТАЛО

Likos
Дмитрий:
Я думаю целью этой статьи автор предполагал не показать алгоритмы решения тех или иных задач, а просто показать людям как выполняется функция кеширования.

Дмитрий
хм поэтому поводу итак хлама довольно, я думаю кроме этого хотел продемонстрировать как правильно эта задача решается с применением ООП для PHP5, но даже этого вобщемто достаточно, просто я ожидал более широкого взгляда под общим заголовком PHP-кеширование или это для заполнения поисковой ниши? заголовк такой)))

Likos
Не исключено. Не буду спорить, но статья мне понравилась, все довольно просто и доступно показано.

M!racle
Дмитрий, никто не говорит удалять 1гбайты кода, удаляется только та часть что отвечает за определенный блок.
Спасибо что сделали вывод по моим кускам кода, мне кажется было бы лучше для всех нас или как минимум для меня что бы вы показали как из этого сделать лучше.
И еще раз, спасибо за кртиику… :)

larin
@Дмитрий
Я долго ждал этого момента! И вот свершилось – мой блог, наконец-то, посетил настоящий знаток программирования и монстр объектного проектирования! Ура!
И вот я и все мои читатели ждем с нетерпением, когда же великий Дмитрий, покажет нам мастер-класс…

Прикол
Хотелось бы услышать насколько такое кеширование еффективно…

larin
Хотелось бы услышать насколько такое кеширование еффективно…
Эффективно )))
Проверено на реальных проектах

Блог web-мастера » Что такое кэширование?
[...] Скажи кэшированию… иногда [...]

Николай
Опередил меня Дмитрий).
Собираю простенькую 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’
Ничего нового не сказал вроде бы). Я так уже делал) Но совсем недавно форматнул диск, бекап наработак не сделал. В итоге теперь я гол как сакол) Хочу все начать сначала, структурировать, ну и сделать красиво

DeadLy

if (false !== $var = $cache->load(’mega’, 10*60)){…}
верно должно быть так, иначе кэш никогда не будет создан
if (false === $var = $cache->load(’mega’, 10*60))
{
…
}

Larin
@DeadLy,
согласен )

phpdude
замечание – правильный интерфейс, но не правильные места у переменных имхо.
проще для запоминания и логичности – так

phpdude
парсер код сожрал :(

phpdude
епт опять … как код запихнуть? )))))))))))))))))

Oleg
Читал диалог с товарищем vasa_c. Пил чай с булочкой и с упоением вчитывался в вашу переписку :) Админу крайняя степень уважения за проявленную выдержку! Видит Бог, я бы не выдержал)

Larin
@Oleg,
спасибо!
Мне кажется, выдержка – это одно из обязательный качеств разработчика ) Заказчики и не такие бывают ;) А vasa_c все таки “коллега по цеху” )
З.Ы.: если не узнали, то admin === Larin

Oleg
Да, само собой, но всему есть предел :) И мой предел товарищ vasa_c нашел бы очень быстро. Я, наверное, очень придирчив, потому не сдержался бы, если бы человек спорил на какую-то тему, не имея достаточного представления о ней. Это я к тому, что vasa_c, судя по всему, не совсем понимает для чего нужно кэширование и как его использовать.
Ну да ладно, забавно было почитать :)

FotoAvto
Так правильно
так

if (!$var = $cache->load('mega', 10*60)) {
или как в комментах
if (false === $var = $cache->load(’mega’, 10*60))
или
if (false !== $var = $cache->load(’mega’, 10*60)){…}

Larin
Правильно:

if (false === $var = $cache->load(’mega’, 10*60)) {}

FotoAvto
О спасибо, вы уже и в статье исправили..

head Gr.
Такой вот топорненький кэш на базе ob_…

$fileName = “cache/” . md5($_SERVER['REQUEST_URI']);
If (time() – @filemtime($fileName) $config['cache_cleanup']*3600)) 
{
$files = glob(‘cache/*’);
$files = array_filter($files, ‘is_file’);
array_map(‘unlink’, $files);
$cached = fopen($fileName, ‘w’);
fwrite($cached, time());
fclose($cached);
}
}
Конструктивная ругань принимается в любых количествах.

Arni
Вы в методе save используете unset. Вопрос. Зачем? Разве после выполнения функции пременные не расторгаются автоматически сборщиком мусора?

Arni
Еще один интересный момент. Чисто гипотетически, может случиться так что кешируемая переменная будет равна $var = ”; Ваш класс, возвращает результат как абсолютную истину после unserialize. И в указанном мною случае, кеширование будет происходить снова и снова. Однозначно что такого случая происходить не должно в принцепе. Но если он случится то ошибку комуто придется искать долго, либо же просто, владелец сайта даже подозревать не будет что происходит постоянное кеширование.


⇓ 

Поделись ссылкой на Seoded.ru с друзьями, знакомыми и собеседниками в соцсетях и на форумах! А сам сайт добавь в закладки! Так победим.

Поделиться ссылкой на эту страницу в:

Полезные ссылки:

Приличный фотограф кеша в Интернете заработает немало В декрете главное — дополнительный заработок

Ещё материалы по этой теме:

Управление зависимостями в PHP-коде Инверсия зависимостей Registry вместо Singleton Статические вызовы Прощай Smarty

основан в 2008 г. © Все права на материалы сайта Seoded.ru принадлежат Алексею Вострову.
Копирование (полное или частичное) любых материалов сайта возможно только с разрешения автора и при указании ссылки на источник.
Ослушавшихся находит и забирает Бабайка!