Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > PHP: Для профи > Псевдо-кэширование на сервере


Автор: Mal Hack 1.2.2006, 16:44
Статья вот тут: http://vingrad.ru/PHP-ART-003003
Обсуждение ниже.

Автор: Opik 18.5.2006, 17:39
Mal Hack, 
Мало, ни memcache, ни Pear:Cache толком ничего нету  

Автор: Mal Hack 18.5.2006, 18:23
Это несколько другое. PEAR я не воспринимаю в принципе. 

Автор: -=Ustas=- 18.5.2006, 22:43
Цитата(Opik @  18.5.2006,  17:39 Найти цитируемый пост)
 ни memcache

Не мог бы малость просветить по этому поводу?!

Mal Hack, такой подход естественно не имеет смысла. Имеет смыл когда контент генерится блоками, и затем эти блоки кэшируются... Лично у меня такой подход... 

Автор: Mal Hack 19.5.2006, 00:06
Цитата(-=Ustas=- @  18.5.2006,  22:43 Найти цитируемый пост)
Mal Hack, такой подход естественно не имеет смысла. Имеет смыл когда контент генерится блоками, и затем эти блоки кэшируются... Лично у меня такой подход...  

Да, это хороший подход. Но не сразу люди видят, как все на блоки разбить, а статья должна дать в данном случае общий алгоритм.
Кстати на счет блоков, не всегда факт.. К примеру есть блок верхней панельки, который зависит от пользователя. Как быть в таком случае?
Да, можно разбить  все на более мелкие блоки, но ИМХО, это не удобно. 

Автор: Opik 19.5.2006, 08:16
Mal Hack, 
Не сказал бы, что это другое.
Насчет не воспринимаешь - вот это другой вопрос, раз взялся писать статью про кеширование, ты должен это сделать непредвзято. Делая не полную статью, ты можешь ввести в заблуждение читателей.

-=Ustas=-, 
http://ee.php.net/memcache
Если коротко: хранение данных в памяти, может использоваться как кеширование. Подробнее по ссылке выше.

Туда же:
http://ee.php.net/apc
http://ee.php.net/shm
http://pear.php.net/package/Cache
http://pear.php.net/package/Cache_Lite 

Автор: -=Ustas=- 19.5.2006, 09:44
Цитата(Mal Hack @  19.5.2006,  00:06 Найти цитируемый пост)
К примеру есть блок верхней панельки, который зависит от пользователя. Как быть в таком случае?

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

Цитата(Mal Hack @  19.5.2006,  00:06 Найти цитируемый пост)
Да, можно разбить  все на более мелкие блоки, но ИМХО, это не удобно.  

Ну это смотря как посмотреть, и смотря какой подход использует сам программист. Например у меня свой класс шаблонов (простой, но работает так как мне надо), он у меня работает с html-шаблонами, в которых хтмл и дескрипторы вида {PANEL}. Т.е. у меня идет блочное формирование, поэтому проблем и запутывания абсолютно нет, все ясно и понятно smile В кратце, допустим есть страница:
Код

<HTML>
<head>
    <title>{TITLE}</title>
</head>
<body>
<table>
    <tr><td>
        {RANDOM}
    </td></tr>
    <tr><td>
        {PANEL}
    </td></tr>
    <tr><td>
        {CONTENT}
    </td></tr>
</table>
</body>
</HTML>

У нас есть три блока, которые заменяются другими блоками подключенных html-шаблонов.
Код

<?php
// index.php

$keyCache = (empty($_SERVER['QUERY_STRING'])) ? 'index' : $_SERVER['QUERY_STRING'];
$keyCache .= (isset($_SESSION['userID'])) ? $_SESSION['userID'] : '';

// Есть методы GetElementCache и MakeElementCache, которые формируют из переданного ключа хеш и проверяют имя файла

// Мы получили этот шаблон $_CONTENT_TMPL
// Теперь нам надо сформировать три блока контента для последующей замены в шаблоне
$_RANDOM_BLOCK  = '';
$_PANEL_BLOCK   = '';
$_CONTENT_BLOCK = '';

// {RANDOM} - получаем его без кеша, т.к. он нам нужен живой, хотя функция GetElementCache принимает 
// параметр - время в минутах (время хранения), можно поставить минут 10, этого достаточно будет, ну да ладно

if (!$_PANEL_BLOCK = GetCacheElement('panel-blocks', $keyCache, 60)) {
    // допустим функция GetCacheElement возращает контент файла кеша, в противном случае FALSE
    // если этот файл уже старый, то функция удаляет его и возращает FALSE
    // если данного файла нет, то формируем этот блок
    ...
    ...
    ...
    ...
    // Сформировали, теперь надо его закешировать
    // при условии что контент поблочный, таким образом $_PANEL_BLOCK 
    // содержит готовый сгеренеренный хтмл
    MakeCacheElement('panel-blocks', $keyCache, $_PANEL_BLOCK);
    // функции передаем имя для файла, ключ для файла, и сам контент блока
    // в итоге у нас получается файлик с именем panel-block-8df17c77af23061ef4322d47d6c431fa.cache
    // который уже при обновлении текущей страницы уже подключиться выше, и генерация контента уже выполняться не будет
    // Все, кеш для данного блока готов
}

...
...
...
// Остальные блоки

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

?>


Конечо, такой подход может показаться на первый взгляд немного муторным, но я уже привык и практически не замечаю этого smile
Зато сервак разгружает очень даже заметно! 

Автор: AztEK 20.5.2006, 08:26
-=Ustas=-,  а как быть с блоками, которые сами по себе генерируются рандомно (типа "случайная новость" и проч.)? И ещё, какая логика у скрипта, управляющим кешированием? В каком случае страница убирается из кеша?

Добавлено @ 08:26 
Виноват, не страница а блок. 

Автор: -=Ustas=- 20.5.2006, 10:55
Цитата(AztEK @  20.5.2006,  08:26 Найти цитируемый пост)
-=Ustas=-,  а как быть с блоками, которые сами по себе генерируются рандомно (типа "случайная новость" и проч.)? 

Я же упомянул об этом smile Такие блоки в кэш не помещать просто напросто.
Цитата(AztEK @  20.5.2006,  08:26 Найти цитируемый пост)
И ещё, какая логика у скрипта, управляющим кешированием? В каком случае страница убирается из кеша?

У меня лично по времени. Но можно дописать что-то вроде проверки контрольной суммы, тогда кэш будет очищаться не по времени, а на момент изменения документа. 

Автор: IZ@TOP 6.6.2006, 08:52
Сейчас появилась интересная тема использования перенаправляющих легких HTTP серверов типа http://nginx.ru. Советую почитать по этой теме. 

Автор: Empirik 8.9.2006, 22:15
Форумчане, по поводу кеширования, скажите пожалуйста, можно ли перехвотить вывод в стандартный поток в php? Ну тоесть перехватить данные которые уходят при помощи вызова функций print и echo ? 

Автор: Mal Hack 8.9.2006, 22:41
Empirik, а я о чем в статье писал???

Автор: Empirik 10.9.2006, 11:34
Ты как раз об этом и писал. Позволь мою мысль объяснить немного конкретней. В класическом случаее кеширование осуществляеться по следующей схеме: все сохраняеться в какую то глобальную переменную, или в простую переменную и потом записываеться в файл и выводиться пользователю. Это не совсем удобно потому, что сначало нужно сформировать весь контент в одной переменной, ну или в нескольких. 
   Меня же интересовало, как можно не формируя контент в одной переменной, а копируя то что уходит пользователю, кешировать страницы.  Поясню примерным примером: 

Стандартный процесс кеширования
Код

$pagebody="";//переменная в котору

$pagebody='<table width="100%">';//собираем страницу или блок 
//....

$pagebody='</table>';

fwrite($fd,$pagebody);//кешируем страницу или блок

print $pagebody//Выводим пользователю


А хотелось бы что бы кеширование производилось следующим образом 

Код

start_cache("some_file_name");//начинаем кеширование

print '<table width="100%">';//собираем страницу или блок 
//....

print '</table>';

end_cache();//заканчиваем кеширование

Автор: Mal Hack 10.9.2006, 11:57
Empirik, читай статью внимательно. Я писал именно о том, КАК ПЕРЕХВАТИТЬ САМ ВЫВОД...
Никаких переменных у меня там нет.

Автор: Vaulter 10.9.2006, 12:17
Empirik, читай про
ob_start();
ob_end_flush();
ob_list_handlers(); например еще smile

Автор: Empirik 10.9.2006, 12:19
Код

ob_start();    
// Тут идет работа скрипта. Т.е., если файла нет,    
// то пользователю будет сгенерирована страница с информацией.    
Print $content;    
$str = ob_get_contents(); // получаем в переменную то, что сгенерировал скрипт.    
/* Создаем кэш файл */    
$f = fopen( «.......» , «w» );    
fwrite( $f , $str );    
fclose( $f );    
ob_end_flush();


Можешь привести код работы функций ob_start() и ob_end_flush() и как я понял, строку 
Print $content; - ты просто написал для примера?

Добавлено @ 12:22 
Всем спасибо разобрался

Автор: Mal Hack 10.9.2006, 12:51
Цитата(Empirik @  10.9.2006,  13:19 Найти цитируемый пост)
Print $content; - ты просто написал для примера?

Да. Это любой вывод в STDOUT.

Автор: Eugene_Bond 10.9.2006, 13:03
добавлю свои 5 копеек

Цитата

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

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

Это же касается "частичного" кеширования страницы ("Тут надо несколько усложнять, и делать кэш частичный, т.е. все что было описано выше надо проделать только над той частью, которая генерирует основной контент").


Ну и главное:
есть тот же Смарти, который замечательно решает все эти вопросы. Как кеширование отдельных шаблонов, так и запрет на кеширование отдельных частей закешированных шаблонов.

Автор: ST_Falcon 1.11.2006, 16:14
Mal Hack, ИМХО для твоего уровня статья слабенькая... все очень поверхносно, не описаны механизмы кеширования в Smarty, PEAR Cache, PEAR Cache Lite. еще было бы очень интересно посмотреть на сравнение производительности при использовании различных инструментов кеширования...

Автор: Mal Hack 1.11.2006, 21:48
Цитата(ST_Falcon @  1.11.2006,  16:14 Найти цитируемый пост)
все очень поверхносно, не описаны механизмы кеширования в Smarty, PEAR Cache, PEAR Cache Lite.

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

Автор: vdim 31.8.2008, 20:21
где статью-то можно почитать?
Ссылка перенаправляет на http://forum.vingrad.ru/faq/topic-82069.html , где одни комментарии.

Автор: Mal Hack 31.8.2008, 21:19
Блин, опять админы со ссылками мутят...
http://base.vingrad.ru/view/2854-Psevdo-keshirovanie-na-servere
http://www.base.vingrad.ru/view/2854-Psevdo-keshirovanie-na-servere

Автор: Sanchezzz 30.6.2009, 07:39
может не к теме немного но вот мой велик на кеш данных:

Код

class cache {
    public  $cache_dir;   // путь до папки с кэшем
    private $time;
    private $lastCache; // последние данные c которыми работали.
    
    public function __construct(){
        $this->cache();
    }

    public function cache(){
        $this->cache_dir = $_SERVER['DOCUMENT_ROOT']."/cache/";
        if(!is_dir($this->cache_dir)){
            mkdir($this->cache_dir , 0755);    
        }
        $this->time = time();        
    }
    // Получить кэш
    public function GetCache($keyName){
        if(file_exists( $this->cache_dir . md5($keyName).".cache"))
            $cache_content = $this->FileRead($this->cache_dir .md5($keyName).".cache" );            
        if(strlen($cache_content)>0)
            $cacheData = unserialize($cache_content);
            else $cacheData = "";
            $this->lastCache = $cacheData;
        return $cacheData;    
    }
    //функция проверяет дату обновления и если вообще кэш
  
    public function isCache($keyName , $timeMinus = 0){
        if(file_exists( $this->cache_dir . md5($keyName).".cache")){
            $cache_content = $this->FileRead($this->cache_dir . md5($keyName).".cache");
            $cacheData = unserialize($cache_content);
            $this->lastCache = $cacheData;
            if((time() - $timeMinus) >= $cacheData['update_time']) return false; else return true;            
        }
        return false;
    }
    
    // Получить временный кэш c которами работали.
    public function GetLastTmpCache(){
        return $this->lastCache;
    }    
    // Записывает кэш
    public function SetCache($var, $keyName , $time = 3600){        
        $cacheData = array();
        //$scalar = is_scalar($var);    
        $cacheData = array(
            'data'=> $var ,                    // данные
            'time'=>$this->time,              // последние изменения
            'update_time'=>$this->time + $time // когда должно обновится
        );                
        $cache_content = serialize($cacheData);    
        $this->FileWrite($this->cache_dir . md5($keyName).".cache" , $cache_content);    
    }
    // Очистить весь кэш
    public function ClearALLCache(){
        $handle = opendir($this->cache_dir);
         while($file = readdir($handle)) {
          if(is_file($file)) unlink($file);        
         }
         closedir($handle);
    }
    // Удалить кэшь по параметру
    public function ClearCache($keyName){
        if($keyName=='') return false;
        $keyName = md5($keyName);
        if(file_exists($this->cache_dir .$keyName )){
            unlink( $this->cache_dir . $keyName );
            return true;
        }
        return false;
    }
    // Открыть файл
    public function FileRead($path){
            clearstatcache(); //нужно
            if(!file_exists($path) || !is_file($path) || !is_readable($path) ) return false;
             if(filesize($path)<=0) return "";
                 $fd = fopen($path, "rb");
                 $contents = fread ($fd, filesize($path));
                 fclose ($fd);
            return $contents;
    }    
    // Перезаписать файл
    public function FileWrite($path, $contents , $unlock = false, $chmod = 0755){
            if(file_exists($path)) chmod($path,$chmod);
            if($file = fopen($path, "w+")){
                  if($unlock!=false) flock($file, LOCK_EX);
                    fwrite($file, $contents);
                  if($unlock!=false) flock($file, LOCK_UN);
                    fclose($file);
                    chmod($path,$chmod);
                    return true;
             } else return false;
    }

}


как пользоватся:
Код

$cache = new cache(); // вызов класса
$writecache = false;

// эта функция проверят если кеш, если есть то берем его и заполняет временный кеш класса.
// если нету то заполняет кеш новыми данными
// _RESULTS_  это для поиска среди кешевых файлов. 
if(!$cache->isCache('_RESULTS_') ){
    $arr = array();
    mysql_connect('localhost','root','');
    mysql_select_db('CMS');
    $res = mysql_query('SELECT * FROM `block_items` WHERE 1');
    
    while ($row = mysql_fetch_assoc($res)):
        $arr[] = $row;
    endwhile;
    //записываем кеш    
    $cache->SetCache($arr, '_RESULTS_');
  $writecache = true; 
}else

// так как вверху используется кашировла проверка isCache
// которая проверяет если кеш, если дата старая то вносим данные новые и заполняем времменный кеш класса

$arr = $cache->GetLastTmpCache(); // отдаем обратно кеш.

print_r($arr);


Минусы и плюсы в этом методе решать вам. 

Автор: Elfet 24.1.2010, 00:13
а где статья? smile

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)