Кэширование части страницы в CodeIgniter

Владимир | | CodeIgniter, PHP, Web разработка.

codeigniter partial cache

CodeIgniter имеет встроенную библиотеку кэширования страниц. Но она работает только с целыми страницами, т.е. вы не можете кэшировать часть страницы.

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

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

Специально для таких случаев я написал небольшую библиотеку (ссылка на архив с ней находится внизу страницы).

Порядок работы с библиотекой такой.

1) Копируете файл partialcache.php в папку application/libraries.

2) Указываете размещение файлов кэша. Параметр $config['cache_path'] (в файле application/config/config.php). Т.е. используется та же папка, что и для основного кэша CodeIgniter.

3) Загружаете библиотеку. Можно использовать любой способ загрузки принятый в CodeIgniter.

4) Для сохранения данных в кэш используется метод save($name, $cacheContent), где $name – имя блока данных (можно использовать любую текстовую строку, главное чтобы она была уникальна для каждого блока), $cacheContent – содержимое блока.

5) Метод get($name, $time = 0) загружает данные из кэша. $name – имя блока данных, $time – время жизни кэша (в минутах).

Приведу небольшой пример.

В одном из прошлых постов, я рассказывал о разделении облака тегов на кластеры и упомянул, что алгоритм достаточно ресурсоемкий. Попробуем кэшировать облако.

Прежде всего, подключаем библиотеку.

$this->load->library('partialcache');

Теперь можно использовать $this->partialcache для работы с кэшем.

if (($data = $this->partialcache->get('my cloud', 1)) === false) {
	$data = serialize($this->tagcloudmodel->getClusteredCloud(2));
	$this->partialcache->save('my cloud', $data);
}
$pageData['clusteredcloud'] = unserialize($data);

Сначала мы вызываем метод get и в его параметрах указываем имя блока данных (my cloud) и время его жизни (1 минута, эту цифру я взял с потолка).

Если метод get возвращает false (кэш не существует или его срок жизни закончился), мы создаем облако заново и сразу же сохраняем его в кэше (с помощью метода save).

В противном случае, в переменной $data будет сохранено содержимое кэша.

После этого, передаем данные в представление (строка 5).

Обратите внимание. Перед сохранением данных в кэш вы должны преобразовать их в строку. Например, для массивов удобно использовать функцию serialize. Естественно, если ваши данные изначально представляют собой набор строк, то никакие преобразования не нужны.

Я провел небольшое тестирование скорости работы кэша и получил такие результаты.

Создание облака тегов и кэша (вызывается метод save) — 0.0138 с.
Создание облака тегов обычным способом (без создания кэша) – 0.0082 с.
Чтение облака тегов из кэша — 0.0043 с.

Т.е. имеем практически двукратное увеличение скорости. Естественно, эффект напрямую зависит от количества тегов и связей между тегами и постами.

Теперь взгляните на исходный код библиотеки:

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); 
/**
 * Этот класс представляет собой библиотеку для фреймворка CodeIgniter,
 * которая предназначена для частичного кэширования web страниц.
 * 
 * Пример использования:
 * 	$this->load->library('partialcache');
 * 	if (($data = $this->partialcache->get('data block name', 5)) === false) {
 *		$data = ; //получение данных обычным способом (например, из БД)
 *		$this->partialcache->save('data block name', $data);
 *	}
 *  //передаем данные в представление
 *	$pageData['view_var_name'] = $data;
 * 
 * Примечание: если нужно сохранять в кэше структуры данных (например, массивы),
 * то предварительно необходимо преобразовать их в строку
 * (например, с помощью функции serialize).
 * 
 * Размещение кэша:
 * 	указывается в $config['cache_path'] (файл application/config/config.php)
 *
 * @author Стаценко Владимир http://www.simplecoding.org <vova_33@gala.net>
 * @version 1.0
 * @package CodeIgniter Library
 */
class PartialCache {
	
	//папка с кэшем
	private $cacheDir = '';
	//количество попыток блокировки файла перед чтением-записью
	private $retries = 5;
	
	function PartialCache() {
		//определяем размещение папки для кэша
		$CI =& get_instance();	
		$path = $CI->config->item('cache_path');
		$this->cacheDir = ($path == '') ? BASEPATH.'cache/' : $path;
	}

	/**
	 * Возвращает блок данных из кэша. Если заданный
	 * блок отсутсвует, возвращает false.
	 *
	 * @param $name - имя блока
	 * @param $time - время жизни кэша (минут)
	 * @return кэшированны блок или false (если он отсутствует)
	 */
	function get($name, $time = 0) {
		$refreshSeconds = ((!is_numeric($time)) ? 0 : $time) * 60;
		$cacheFile = md5($name);
		if (file_exists($this->cacheDir.$cacheFile) &&
				((time() - filemtime($this->cacheDir.$cacheFile)) < $refreshSeconds)) {
			//читаем данные из файла
			$fp = fopen($this->cacheDir.$cacheFile, 'rb');
			//блокируем файл для записи
			$curTry = 1;
			do {
				if ($curTry > 1) {
					usleep(rand(100, 10000));
				}
			} while (!flock($fp, LOCK_SH) && (++$curTry <= $this->retries));
			
			//не смогли заблокировать файл
			if ($curTry == $this->retries) {
				return false;
			}
			
			//читаем данные из файла
			$cacheContent = '';
			if (filesize($this->cacheDir.$cacheFile) > 0) {
				$cacheContent = fread($fp, filesize($this->cacheDir.$cacheFile));
			}
			
			//снимаем блокировку
			flock($fp, LOCK_UN);
			//закрываем файл
			fclose($fp);
			
			return $cacheContent;
		}
		return false;
	} 

	/**
	 * Сохраняет блок данных в кэше
	 *
	 * @param $name - имя блока с кэшем
	 * @param $cacheContent - содержимое блока
	 * @return true - если блок сохранен, false - в противном случае
	 */
	function save($name, $cacheContent) {
		//проверяем возможна ли запись в папку с кэшем
		if (!$this->_checkCacheDir()) {
			return false;
		}
		
		//открываем файл для записи
		$cacheFile = md5($name);
		$fp = fopen($this->cacheDir.$cacheFile, 'wb');
		if (!$fp) {
			return false;
		}
		
		//блокируем файл перед записью
		$curTry = 1;
		do {
			if ($curTry > 1) {
				usleep(rand(100, 10000));
			}
		} while (!flock($fp, LOCK_EX) && (++$curTry <= $this->retries));
		
		//не смогли заблокировать файл
		if ($curTry == $this->retries) {
			return false;
		}
		
		//записываем в файл
		fwrite($fp, $cacheContent);
		//снимаем блокировку и закрываем файл
		flock($fp, LOCK_UN);
		fclose($fp);
		@chmod($this->cacheDir.$cacheFile, 0777);

		log_message('debug', "Cache file written: ".$this->cacheDir.$cacheFile);
				
		return true;
	} 

	/**
	 * Проверяет возможна ли запись в папку кэша.
	 * Если возможна возвращает true, если нет - false.
	 *
	 * @return true - если запись возможна, false - если нет
	 */
	function _checkCacheDir() {
		if ( !is_dir($this->cacheDir) OR !is_really_writable($this->cacheDir))
		{
			return false;
		}
		return true;
	}
}
?>

Код получился довольно длинным, но в основном из-за различных проверок.

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

Но при этом возникает другая проблема. Если файл заблокирован, а скрипт вызвал метод save, то кэш создан не будет. Чтобы решить проблему методы get и save делают 5 попыток заблокировать файл (строки 57-61 и 106-110) (количество задается свойством $retries). Между попытками скрипт приостанавливает работу на время от 0,1 до 10 мс.

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

Скачать библиотеку.

Архив с библиотекой PartialCache.

До встречи!

P.S. Если вы обнаружите недостатки или ошибки, пожалуйста, сообщите мне об этом. Буду исправлять 😉 .

  • а мемкашед использовать не судьба?
    плюс насчёт отдельных блоков — их можно определить как приватные методы и вызывать их из публичного.

    • memcached создает кэш в памяти, а не файлах.
      В общем-то я согласен, что для этого примера memcached подходит лучше, да и работать будет быстрее.
      Кроме того, доступ к файлам есть всегда, а memcached — нет (если речь о shared хостинге).

  • а мемкашед использовать не судьба?
    плюс насчёт отдельных блоков — их можно определить как приватные методы и вызывать их из публичного.

    • memcached создает кэш в памяти, а не файлах.
      В общем-то я согласен, что для этого примера memcached подходит лучше, да и работать будет быстрее.
      Кроме того, доступ к файлам есть всегда, а memcached — нет (если речь о shared хостинге).

  • MAX

    Очень странный алгоритм… Обычно время жизни кэша указывается при записи в него. А когда он считывается, то смотрится указанное время и если оно превышено, то возвращается false (или какое-то дефолтное значение).

    Вообще в CodeIgniter есть уже неплохой кэш в output.php. Я его немного переделал для своей MaxSite CMS и он вполне неплохо себя зарекомендовал.

    • Очень странный алгоритм

      Да, я в курсе 😉 . Стандартный кэш в CI записывает метку времени в начало файла, а потом читает ее.
      Мне показалось, что проще указать время жизни при чтении кэша (метод get). Просто сначала была идея указывать дефолтное время жизни в конфиге.

      Вообще в CodeIgniter есть уже неплохой кэш

      Только он кэширует всю страницу целиком. В некоторых случаях это не самый удачный вариант.

      • MAX

        Ну да, целиком. Поэтому проще переделать его функцию (в хелпер, например) и использовать там где нужно.

        Лично я совсем не уверен в правильности ввода задержки flock в get-методе. Тут же как раз задача как можно быстрей получить файл. А у тут как раз задержка, да еще и с блокировкой сложновастенько получается. По алгоритму CodeIgniter такого варианта просто не получится: если файл недоступен, то будет выполнена функция, а в её конце данные опять попадут в кэш. Ничего не теряется.

        • Задержки можно и убрать ($retries = 0;)
          Вопрос в другом. Что будет если действительно возникнет одновременная запись в файл (или запись и чтение)?
          В CI (файл Output.php, строки 307-309) код такой:

          flock($fp, LOCK_EX);
          fwrite($fp, $expire.'TS--->'.$output);
          flock($fp, LOCK_UN);

          Т.е. делается попытка заблокировать файл и независимо от результата — запись.
          Я не уверен, что здесь не могут возникнуть ошибки.

        • MAX

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

          1. У нас есть ключ. Он преобразуется в имя файла. Имя уникально.
          2. Вначале мы считываем данные из кэша по этому ключу. Файл быстро открывается на чтение, но при этом имеет разделяемый доступ (LOCK_SH). Таким образом мы сразу получаем данные из кэша (если есть).
          3. В конце рабочей функции у нас стоит запись в кэш по этому же ключу. То есть сама запись в файл будет только в случае, если кэша нет или он испорчен, но при этом у нас чтение и запись выполняются в разных местах кода и пока не отработает функция чтения, не запустится функция записи.

          Вот. 🙂

        • Похоже я что-то не до конца понимаю или не так объясняю.

          Допустим у нас есть кэш с временем жизни до 12:00:00.000
          Первый посетитель зашел на сайт в 11:59:59.999, т.е. кэш еще актуален и скрипт начал чтение из файла. Допустим чтение занимает 0.01 с, т.е. закончится в 12:00:00.009.
          В 12:00:00.001 на сайт заходит другой посетитель. Apache создает новый поток (thread), т.е. два скрипта выполняются параллельно.
          Скрипт из второго потока обнаруживает, что кэш устарел и начинает запись в него. До того, как первый поток закончит чтение, т.к. результат который возвращает flock($fp, LOCK_EX); не учитывается при работе скрипта.
          Что произойдет?

        • MAX

          кэш устарел и начинает запись в него.

          Ничего подобного! Запись в кэш происходит только в конце самой функции. Если кэш устарел, то вначале выполняется функция, которая заведомо длительней чем чтение с диска (а иначе какой смысл в кэше?) и только потом идет запись в файл. Но, даже если предположить, что будет две одновременных записи в файл и обе закончатся неудачно, то ничего страшного не происходит — кэш просто остается пустым и в следующий раз при вызове функции опять будет попытка записи.

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

          🙂

        • заведомо длительней чем чтение с диска

          Дошло 🙂 Как раз этот момент я упустил из виду. Спасибо!

  • MAX

    Очень странный алгоритм… Обычно время жизни кэша указывается при записи в него. А когда он считывается, то смотрится указанное время и если оно превышено, то возвращается false (или какое-то дефолтное значение).

    Вообще в CodeIgniter есть уже неплохой кэш в output.php. Я его немного переделал для своей MaxSite CMS и он вполне неплохо себя зарекомендовал.

    • Очень странный алгоритм

      Да, я в курсе 😉 . Стандартный кэш в CI записывает метку времени в начало файла, а потом читает ее.
      Мне показалось, что проще указать время жизни при чтении кэша (метод get). Просто сначала была идея указывать дефолтное время жизни в конфиге.

      Вообще в CodeIgniter есть уже неплохой кэш

      Только он кэширует всю страницу целиком. В некоторых случаях это не самый удачный вариант.

      • MAX

        Ну да, целиком. Поэтому проще переделать его функцию (в хелпер, например) и использовать там где нужно.

        Лично я совсем не уверен в правильности ввода задержки flock в get-методе. Тут же как раз задача как можно быстрей получить файл. А у тут как раз задержка, да еще и с блокировкой сложновастенько получается. По алгоритму CodeIgniter такого варианта просто не получится: если файл недоступен, то будет выполнена функция, а в её конце данные опять попадут в кэш. Ничего не теряется.

        • Задержки можно и убрать ($retries = 0;)
          Вопрос в другом. Что будет если действительно возникнет одновременная запись в файл (или запись и чтение)?
          В CI (файл Output.php, строки 307-309) код такой:

          flock($fp, LOCK_EX);
          fwrite($fp, $expire.'TS--->'.$output);
          flock($fp, LOCK_UN);

          Т.е. делается попытка заблокировать файл и независимо от результата — запись.
          Я не уверен, что здесь не могут возникнуть ошибки.

        • MAX

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

          1. У нас есть ключ. Он преобразуется в имя файла. Имя уникально.
          2. Вначале мы считываем данные из кэша по этому ключу. Файл быстро открывается на чтение, но при этом имеет разделяемый доступ (LOCK_SH). Таким образом мы сразу получаем данные из кэша (если есть).
          3. В конце рабочей функции у нас стоит запись в кэш по этому же ключу. То есть сама запись в файл будет только в случае, если кэша нет или он испорчен, но при этом у нас чтение и запись выполняются в разных местах кода и пока не отработает функция чтения, не запустится функция записи.

          Вот. 🙂

        • Похоже я что-то не до конца понимаю или не так объясняю.

          Допустим у нас есть кэш с временем жизни до 12:00:00.000
          Первый посетитель зашел на сайт в 11:59:59.999, т.е. кэш еще актуален и скрипт начал чтение из файла. Допустим чтение занимает 0.01 с, т.е. закончится в 12:00:00.009.
          В 12:00:00.001 на сайт заходит другой посетитель. Apache создает новый поток (thread), т.е. два скрипта выполняются параллельно.
          Скрипт из второго потока обнаруживает, что кэш устарел и начинает запись в него. До того, как первый поток закончит чтение, т.к. результат который возвращает flock($fp, LOCK_EX); не учитывается при работе скрипта.
          Что произойдет?

        • MAX

          кэш устарел и начинает запись в него.

          Ничего подобного! Запись в кэш происходит только в конце самой функции. Если кэш устарел, то вначале выполняется функция, которая заведомо длительней чем чтение с диска (а иначе какой смысл в кэше?) и только потом идет запись в файл. Но, даже если предположить, что будет две одновременных записи в файл и обе закончатся неудачно, то ничего страшного не происходит — кэш просто остается пустым и в следующий раз при вызове функции опять будет попытка записи.

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

          🙂

        • заведомо длительней чем чтение с диска

          Дошло 🙂 Как раз этот момент я упустил из виду. Спасибо!

  • Код хорошо написан, но есть некоторые непонятности.
    1. Время хранения кеша действительно принято хранить во время записи.
    2. Совершенно ненужно делать md5(). Достаточно обусловиться писать названия английскими символами (тем более что для любого разработчика это интуитивно понятно). Ну и конечно помнить о регистрозависимости в случае unix систем. А можно вообще пропускать название, кк это все делают через strtolower().
    3. Сблокировками вы вообще намудрили. Просто нужно делать не разделяемую блокировку при записи, а исключительную LOCK_EX. Тогда во время записи, другие потоки несмогут читать. В итоге метод get() вернет false и все будет работать.
    Обращение к ресурсам файловой системы всегда относительно дорого, поэтому в гете блокировкам неместо.

  • Код хорошо написан, но есть некоторые непонятности.
    1. Время хранения кеша действительно принято хранить во время записи.
    2. Совершенно ненужно делать md5(). Достаточно обусловиться писать названия английскими символами (тем более что для любого разработчика это интуитивно понятно). Ну и конечно помнить о регистрозависимости в случае unix систем. А можно вообще пропускать название, кк это все делают через strtolower().
    3. Сблокировками вы вообще намудрили. Просто нужно делать не разделяемую блокировку при записи, а исключительную LOCK_EX. Тогда во время записи, другие потоки несмогут читать. В итоге метод get() вернет false и все будет работать.
    Обращение к ресурсам файловой системы всегда относительно дорого, поэтому в гете блокировкам неместо.

  • Зачем rand() тоже несовсем понятно. Нужно просто поставить фиксированное число. У вас в каждой итерации вычисляеться лишняя орперация.
    А можно вообще ввести систему единого таймаута

    • md5 — стандартный вариант хранения кэша в CI. Конечно, использовать его не обязательно.

      Блокировки. Честно говоря, я использовал готовое решение, которое мне просто понравилось и показалось достаточно надежным. Оригинал тут (первый комментарий).

      rand() наверное лучше действительно убрать или использовать другие значения задержек. Тут я не додумал.

  • Зачем rand() тоже несовсем понятно. Нужно просто поставить фиксированное число. У вас в каждой итерации вычисляеться лишняя орперация.
    А можно вообще ввести систему единого таймаута

    • md5 — стандартный вариант хранения кэша в CI. Конечно, использовать его не обязательно.

      Блокировки. Честно говоря, я использовал готовое решение, которое мне просто понравилось и показалось достаточно надежным. Оригинал тут (первый комментарий).

      rand() наверное лучше действительно убрать или использовать другие значения задержек. Тут я не додумал.

  • хорошая работа..реально видно что пишете сами) вам посложней чем говноблогам с перепечатывванием аналогов)

  • хорошая работа..реально видно что пишете сами) вам посложней чем говноблогам с перепечатывванием аналогов)

  • Мне скрипт очень понравился! Очень полезная вещь! Спасибо, буду использовать!

  • Мне скрипт очень понравился! Очень полезная вещь! Спасибо, буду использовать!

  • Big_Shark

    Зачем лишние заморочки с временим, жизни КЭШа ведь это в большинстве случаев не нужно предположим у вас есть огромное меню с подкаталогами которое грузиться долго с 5 разных таблиц, и вы его обновляете максимум 1-2 раза в месяц можно проста, записать кэш с именем 'menu' а при изменении меню в админ панели удалять файл с КЭШам и все. Название через md5 не прогоняются, поэтому в любой момент можно зайти посмотреть какая информация лежит в файле.
    Минусы записывать и считывать можно только массивы.
    Плюсы при записи и считывании не нужно заботиться о serialize и unserialize

    Есть свой класс КЭШа намой взгляд более удобный чем предложенный тут но его нужно переделать для CodeIgniter кому хочется на нее посмотреть или переделать для CodeIgniter пишите на мыло Big_Shark@mail.ru или в асю 231744674 я скину.

    • Для примера, который вы привели, действительно кэш имеет смысл обновлять только при обновлении БД. Но если данные обновляются постоянно, то без лучше задавать времени жизни. Конечно, при этом часть пользователей может увидеть устаревшие данные, но тут все зависит от приложения (и разработчика).

      • Big_Shark

        Ну, если даже данные обновляются каждые 10 минут, а пользователь заходит каждую минуту то в вашем варианте даже если поставить кэш на 10 минут все будут видеть, то, что и должны, но если информация не будет изменяться Кэш все равно будет скидываться и записываться заново это неправильно, в моем варианте если кэш скидывать при изменении, то 1 из 9 пользователей будут погружать последнею версию данных другие видеть кэш. Можно сделать еще 1 вариант после обновления информации ее сразу загружать с кэш по тому же принципу что и пользователь и в таком случае вообще не будет для пользователя не каких лишних загрузок из базы, а только КЭШа.

        • Я, наверное, не совсем удачно объяснил. Речь идет о ситуациях когда невозможно (с точки зрения производительности) обновлять кэш каждый раз когда изменяются данные. Например, возьмем тотже Feedburner. Периодичность обновления ленты у них по-моему 30 мин (не помню точно). Т.е. если вы опубликуете два поста с интервалом минут 10, то они появятся в ленте feedburner'а они могут появиться одновременно, хотя в ленте вашего блога они окажутся сразу после публикации. По сути это тотже самый кэш.
          Естественно, посетители какое-то время будут видеть устаревшую версию кэша.

        • Big_Shark

          Ну в этом случае и кэш не обязательно на сколько я понимаю если он все ровно каждые 30 минут делает обращения к базе за новой информацией)

        • Кэш на создает feedburner.
          Или другой пример. Вы пишите систему интернет-статистики, вроде liveinternet. Т.е. в идеале нужно генерировать новую картинку каждый раз когда кто-то обращается к страницам на которых размещен счетчик. Но если создавать картинку не при каждом обращении, а только раз в 10 мин, то можно сэкономить ресурсы (если сайт популярный и каждые 10 мин происходит более 1 обращения).

  • Big_Shark

    Зачем лишние заморочки с временим, жизни КЭШа ведь это в большинстве случаев не нужно предположим у вас есть огромное меню с подкаталогами которое грузиться долго с 5 разных таблиц, и вы его обновляете максимум 1-2 раза в месяц можно проста, записать кэш с именем 'menu' а при изменении меню в админ панели удалять файл с КЭШам и все. Название через md5 не прогоняются, поэтому в любой момент можно зайти посмотреть какая информация лежит в файле.
    Минусы записывать и считывать можно только массивы.
    Плюсы при записи и считывании не нужно заботиться о serialize и unserialize

    Есть свой класс КЭШа намой взгляд более удобный чем предложенный тут но его нужно переделать для CodeIgniter кому хочется на нее посмотреть или переделать для CodeIgniter пишите на мыло Big_Shark@mail.ru или в асю 231744674 я скину.

    • Для примера, который вы привели, действительно кэш имеет смысл обновлять только при обновлении БД. Но если данные обновляются постоянно, то без лучше задавать времени жизни. Конечно, при этом часть пользователей может увидеть устаревшие данные, но тут все зависит от приложения (и разработчика).

      • Big_Shark

        Ну, если даже данные обновляются каждые 10 минут, а пользователь заходит каждую минуту то в вашем варианте даже если поставить кэш на 10 минут все будут видеть, то, что и должны, но если информация не будет изменяться Кэш все равно будет скидываться и записываться заново это неправильно, в моем варианте если кэш скидывать при изменении, то 1 из 9 пользователей будут погружать последнею версию данных другие видеть кэш. Можно сделать еще 1 вариант после обновления информации ее сразу загружать с кэш по тому же принципу что и пользователь и в таком случае вообще не будет для пользователя не каких лишних загрузок из базы, а только КЭШа.

        • Я, наверное, не совсем удачно объяснил. Речь идет о ситуациях когда невозможно (с точки зрения производительности) обновлять кэш каждый раз когда изменяются данные. Например, возьмем тотже Feedburner. Периодичность обновления ленты у них по-моему 30 мин (не помню точно). Т.е. если вы опубликуете два поста с интервалом минут 10, то они появятся в ленте feedburner'а они могут появиться одновременно, хотя в ленте вашего блога они окажутся сразу после публикации. По сути это тотже самый кэш.
          Естественно, посетители какое-то время будут видеть устаревшую версию кэша.

        • Big_Shark

          Ну в этом случае и кэш не обязательно на сколько я понимаю если он все ровно каждые 30 минут делает обращения к базе за новой информацией)

        • Кэш на создает feedburner.
          Или другой пример. Вы пишите систему интернет-статистики, вроде liveinternet. Т.е. в идеале нужно генерировать новую картинку каждый раз когда кто-то обращается к страницам на которых размещен счетчик. Но если создавать картинку не при каждом обращении, а только раз в 10 мин, то можно сэкономить ресурсы (если сайт популярный и каждые 10 мин происходит более 1 обращения).

  • Big_Shark

    Вот это хороший и правельный пример вы привели )
    Но насколько я понимаю ваша система кеша не сможет создавать картинку а только файлы с текстом)

    • Да, тут вы правы, для работы с картинками код нужно доработать 🙂
      Но, с другой стороны, в кэше можно хранить ссылку на нужный файл, а сами файлы будет создавать основной скрипт (если ссылка в кэше устарела). Правда, придется как-то удалять старые файлы, но это уже другой вопрос 😉 .

      • Big_Shark

        А можно создавать картину, у которой в названии дата, а потом раз в неделю удалять их. Много разных способов и методов КЭШа. Кто та кэширует результат запроса, кто та массив перед выводом, а кто та кэширует то, что вывел. Но все сходятся в 1, в том, что кэш необходим.

        Как вы смотрите на то, чтобы я вам присылал кое, какие свои скрипты с описанием их работы и если они вам понравятся, вы будете их также освещать?

        • Я не против 🙂
          Но у меня встречный вопрос: «Как вы смотрите на то, чтобы открыть собственный блог?». Вы сможете рассказать о своих скриптах или идеях гораздо подробнее.
          К тому же, если скрипт хороший и вы хотите им поделиться, то неплохо бы сделать отдельную страницу под него (со ссылками на архив с исходниками и документацию).

        • Big_Shark

          Я не писатель я программист.
          Я не могу доходчиво объяснять так чтобы понял человек с любым уровнем знаний. Поэтому и хочу чтобы вы описывали скрипты так как у вас это хорошо получается. Я в основном выкладываю скрипты не для конечных пользователей, а для тех которые их могут чуть-чуть подогнать под себя и тогда скрипт раскроет все смою гибкость и мощность. В скором времени начну писать CMS на CodeIgniter надеюсь там уже и буду выкладывать все свои скрипты.

        • Я тоже не писатель 🙂
          И мои статьи врядли поймет человек не знакомый с программированием.
          Но я с удовольствием напишу об интересных скриптах 🙂

          Кстати, если вы хотите распространять скрипты, то нужно подумать о хостинге. Хотя бы одна страница с кратким описанием возможностей, ссылками и вашими контактными данными. Ну и changelog нужен чтобы видно было, что работа идет 🙂 . В идеальном варианте — хостинг с subversion.

          А CMS на CodeIgniter — это всегда интересно. Я уже писал о MaxSite CMS, поэтому посмотреть на альтернативные решения будет очень интересно.

        • Big_Shark

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

        • Присылайте, буду ждать 😉

  • Big_Shark

    Вот это хороший и правельный пример вы привели )
    Но насколько я понимаю ваша система кеша не сможет создавать картинку а только файлы с текстом)

    • Да, тут вы правы, для работы с картинками код нужно доработать 🙂
      Но, с другой стороны, в кэше можно хранить ссылку на нужный файл, а сами файлы будет создавать основной скрипт (если ссылка в кэше устарела). Правда, придется как-то удалять старые файлы, но это уже другой вопрос 😉 .

      • Big_Shark

        А можно создавать картину, у которой в названии дата, а потом раз в неделю удалять их. Много разных способов и методов КЭШа. Кто та кэширует результат запроса, кто та массив перед выводом, а кто та кэширует то, что вывел. Но все сходятся в 1, в том, что кэш необходим.

        Как вы смотрите на то, чтобы я вам присылал кое, какие свои скрипты с описанием их работы и если они вам понравятся, вы будете их также освещать?

        • Я не против 🙂
          Но у меня встречный вопрос: «Как вы смотрите на то, чтобы открыть собственный блог?». Вы сможете рассказать о своих скриптах или идеях гораздо подробнее.
          К тому же, если скрипт хороший и вы хотите им поделиться, то неплохо бы сделать отдельную страницу под него (со ссылками на архив с исходниками и документацию).

        • Big_Shark

          Я не писатель я программист.
          Я не могу доходчиво объяснять так чтобы понял человек с любым уровнем знаний. Поэтому и хочу чтобы вы описывали скрипты так как у вас это хорошо получается. Я в основном выкладываю скрипты не для конечных пользователей, а для тех которые их могут чуть-чуть подогнать под себя и тогда скрипт раскроет все смою гибкость и мощность. В скором времени начну писать CMS на CodeIgniter надеюсь там уже и буду выкладывать все свои скрипты.

        • Я тоже не писатель 🙂
          И мои статьи врядли поймет человек не знакомый с программированием.
          Но я с удовольствием напишу об интересных скриптах 🙂

          Кстати, если вы хотите распространять скрипты, то нужно подумать о хостинге. Хотя бы одна страница с кратким описанием возможностей, ссылками и вашими контактными данными. Ну и changelog нужен чтобы видно было, что работа идет 🙂 . В идеальном варианте — хостинг с subversion.

          А CMS на CodeIgniter — это всегда интересно. Я уже писал о MaxSite CMS, поэтому посмотреть на альтернативные решения будет очень интересно.

        • Big_Shark

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

        • Присылайте, буду ждать 😉

  • Спасибо, очень кстати наткнулся на заметку, а то сам собирался писать небольшую библиотечку. Наверное имеет смысл разносить кеш по субдиректориям. Хотя бы по первому символу или по паре первых символов… У меня в одном проекте на Joomla кеш каталога составляет около 20000 файлов и скорость чтения/записи уже сильно зависит от файловой системы…

    • Если использовать в качестве названий md5 суммы имен файлов, то 20000 разных названий — не проблема.
      А вот скорость чтения/записи действительно зависит от файловой системы и вообще скорости работы дисковой подсистемы.

      Наверное имеет смысл держать часть кеша в памяти.

      Насчет скорости работы с субдиректориями не уверен. Нужно тестировать.

      • Big_Shark

        Действительно лучше разносить по субдеректориям но я опять же предлогаю делать без md5 типа open(cat/news/id_5) и тд и в последствии несоставит труда дописать функцию по удалению всего кеша из папкп cat или cat/news

        • Если эти функции для данного проекта нужны, то согласен, с папками будет намного удобнее.
          md5 сумма практически 100% гарантирует уникальные имена файлов кэша, поэтому и используется часто.

        • Big_Shark

          Если программист не дурак он и сам может генерировать имя для кадого файла кеша используя разные переменные и ад
          зато потом понятно глядя на кеш чего у тебя больше закеширована и можна отчишать кеш по маске гораздо быстрей и удобней мне кажеться
          а можна и вручную через фтп отчистить кеш определенного модуля .
          Я понимаю можна через md5 прогонять пароли куки сесии и тд все что нужно шифровать но файлы это уже слишком!

          p.s. md5 практически 100% гарантирует уникальные имена а гарантирую что искпользую 100% уникальное имя)

        • шифровать но файлы это уже слишком

          Нет, сам файл никто не шифрует, только имя

          Я согласен, система с папками имеет свои преимущества. Но могут возникнуть проблемы, например, нужно учитывать ситуации когда администратор переименовывает раздел (название которого совпадает с названием папки кэша).

          Хотя, конечно, с папками ориентироваться в файлах кэша гораздо удобнее.

        • Big_Shark

          ну а так он будет заходить и видеть кучу папок с непонятными именами.

          У меня сейчас 7 тысяч файлов кеша и нету не какой путаницы я понимаю где кеш какого модуля лежит и за что он отвечает!

        • А сколько раз приходилось вручную кеш редактировать? 😉

        • Big_Shark

          Раз 5) но если бы я не имел возможности отредактировать кеш вручную пришлось бы ждать около 4 часов пока парсер снова спарсит инфу разобьет как нада и создаст файлы для записи в базу а кеш скидывать полностью практически не возможно ибо только поименовоного кеша больше 7 тысяч и еще кеша с базы больше 15 тысяч
          при сбросе кжша сайт прсота начинает подвисать жутко!

        • Весело 🙂
          Нужен отдельный сервер для создания кэша 🙂 Примерно так делают на фотохостингах. Один сервер (или несколько) раздают контент, а другой занимается кодированием в общий формат.

          А если серьезно, из-за чего возникли ошибки в кеше?

        • Big_Shark

          Парсяться большие прайсы и при написании я промахнулся и забыл заэкронировать ковычки парсер работает около 4 часок и чтобы снова его не запускать я вручную поменял в нескольких элементах данные и вписал экронирования в код вот и все)
          Ну несколько серверов сильно накладно хотя конечно эффективно)

  • Спасибо, очень кстати наткнулся на заметку, а то сам собирался писать небольшую библиотечку. Наверное имеет смысл разносить кеш по субдиректориям. Хотя бы по первому символу или по паре первых символов… У меня в одном проекте на Joomla кеш каталога составляет около 20000 файлов и скорость чтения/записи уже сильно зависит от файловой системы…

    • Если использовать в качестве названий md5 суммы имен файлов, то 20000 разных названий — не проблема.
      А вот скорость чтения/записи действительно зависит от файловой системы и вообще скорости работы дисковой подсистемы.

      Наверное имеет смысл держать часть кеша в памяти.

      Насчет скорости работы с субдиректориями не уверен. Нужно тестировать.

      • Big_Shark

        Действительно лучше разносить по субдеректориям но я опять же предлогаю делать без md5 типа open(cat/news/id_5) и тд и в последствии несоставит труда дописать функцию по удалению всего кеша из папкп cat или cat/news

        • Если эти функции для данного проекта нужны, то согласен, с папками будет намного удобнее.
          md5 сумма практически 100% гарантирует уникальные имена файлов кэша, поэтому и используется часто.

        • Big_Shark

          Если программист не дурак он и сам может генерировать имя для кадого файла кеша используя разные переменные и ад
          зато потом понятно глядя на кеш чего у тебя больше закеширована и можна отчишать кеш по маске гораздо быстрей и удобней мне кажеться
          а можна и вручную через фтп отчистить кеш определенного модуля .
          Я понимаю можна через md5 прогонять пароли куки сесии и тд все что нужно шифровать но файлы это уже слишком!

          p.s. md5 практически 100% гарантирует уникальные имена а гарантирую что искпользую 100% уникальное имя)

        • шифровать но файлы это уже слишком

          Нет, сам файл никто не шифрует, только имя

          Я согласен, система с папками имеет свои преимущества. Но могут возникнуть проблемы, например, нужно учитывать ситуации когда администратор переименовывает раздел (название которого совпадает с названием папки кэша).

          Хотя, конечно, с папками ориентироваться в файлах кэша гораздо удобнее.

        • Big_Shark

          ну а так он будет заходить и видеть кучу папок с непонятными именами.

          У меня сейчас 7 тысяч файлов кеша и нету не какой путаницы я понимаю где кеш какого модуля лежит и за что он отвечает!

        • А сколько раз приходилось вручную кеш редактировать? 😉

        • Big_Shark

          Раз 5) но если бы я не имел возможности отредактировать кеш вручную пришлось бы ждать около 4 часов пока парсер снова спарсит инфу разобьет как нада и создаст файлы для записи в базу а кеш скидывать полностью практически не возможно ибо только поименовоного кеша больше 7 тысяч и еще кеша с базы больше 15 тысяч
          при сбросе кжша сайт прсота начинает подвисать жутко!

        • Весело 🙂
          Нужен отдельный сервер для создания кэша 🙂 Примерно так делают на фотохостингах. Один сервер (или несколько) раздают контент, а другой занимается кодированием в общий формат.

          А если серьезно, из-за чего возникли ошибки в кеше?

        • Big_Shark

          Парсяться большие прайсы и при написании я промахнулся и забыл заэкронировать ковычки парсер работает около 4 часок и чтобы снова его не запускать я вручную поменял в нескольких элементах данные и вписал экронирования в код вот и все)
          Ну несколько серверов сильно накладно хотя конечно эффективно)

  • Валерий

    Кстати почему в коде у вас везде метасиволы. Читать невозможно. В редакотре просто нельзя работать в режиме визивига после того как ввели в окно код. И тогда будет все нормально.

    • Визуальный режим в редакторе у меня давно отключен. То, что вы видели — результат не очень удачного эксперимента с плагинами. Сейчас должно быть все нормально :-).

  • Валерий

    Кстати почему в коде у вас везде метасиволы. Читать невозможно. В редакотре просто нельзя работать в режиме визивига после того как ввели в окно код. И тогда будет все нормально.

    • Визуальный режим в редакторе у меня давно отключен. То, что вы видели — результат не очень удачного эксперимента с плагинами. Сейчас должно быть все нормально :-).

  • Руслан

    Спасибо большое!!!!

  • Руслан

    Напишите урок плиз!
    вот у меня например есть следующий код:

    — Это начало кэширование
    $this->load->view('header');
    — Это конец
    $this->load->view('content',$data);
    — Это начало кэширование
    $this->load->view('footer');
    — Это конец

    • Я не совсем понял что именно вы хотите почитать?

  • Netu

    OTSTOY!!!

  • Netu

    OTSTOY!!!