Кэш в файлах

Аватар пользователя larin larin 20 июля 2008 в 6:35

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

Основные идеи:
1. Простота.
2. По возможности не дёргать БД. за счёт этого страница из кэша отдаётся в несколько сотен раз быстрее, чем обычная.
3. Кэшируем только анонимов. Если им разрешены постинги - будут проблемы.

Реализация:
1. Создать папку для кэша: mkdir /tmp/cache, chmod 777 /tmp/cache
2. В index.php, в самом начале, до bootstrap (<?phprequire_once './includes/bootstrap.inc';drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);?>) добавить:

<?php
Global $time1;
$time1 microtime(1);
 
function 
logcache($s) {
  Global 
$time1;
  
$log fopen("/var/log/drupal-cache.log"'a');
  
fwrite ($log$s.', ' . ((int)(1000*(microtime(1) - $time1))) . " ms used\n");
  
fclose ($log);
}
 
$req $_SERVER['REQUEST_URI'];
if (empty(
$_POST) && !isset($_COOKIE['drupal_uid']) && !strstr($req'/admin') && !strstr($req'AJAX')) { 
  
$f '/tmp/cache/'.strtr($req'/''_');
  if (
file_exists($f) && time() - filemtime($f) < 13*60) {
    
readfile($f);
    
logcache ("+ $req served from cache");
    exit;
  } else {
    
ob_start();
  }
} else {
  
$f '';
}
?>

3. В самом конце, после drupal_page_footer():

<?php
Global $user;
if (
$user->uid)    setcookie('drupal_uid'$user->uidtime() + (60 60 24 30), '/');
 
Global 
$nofilecache;
if (!
$nofilecache && $f) {
  if (
file_exists($f)) $cachetime = (int)((time() - filemtime($f))/60);
  
$fh fopen($f'w');
  
fwrite($fhob_get_contents());
  
fclose($fh);
  
ob_end_flush();
  if (
$cachetimelogcache("- $req replaced - has $cachetime min old");
  else 
logcache ("- $req created cache");
} else {
  
logcache ("* $req no cache, uid = ".$_COOKIE['drupal_uid']);
}
?>

4. В includes/common.inc, в начале функции drupal_goto, чтобы не кэшировать редиректы

<?php
  
Global $nofilecache;
  
$nofilecache 1;
?>

5. В крон:

11 * * * * find /tmp/cache/ -mmin 15 -delete

Сервер разгружается весьма заметно.
Сейчас работает на http://lib.rus.ec, проблем не замечено.

Комментарии

Аватар пользователя VladSavitsky VladSavitsky 20 июля 2008 в 13:15

Позволил себе разукрасить ваш код в разные цвета... Lol
Спасибо за решение.
Можно ли его применять и в Д5, и в Д6?

Аватар пользователя larin larin 20 июля 2008 в 22:59

Спасибо, так смотрится лучше.
Я применяю Д6, но должно работать в любом. Всё же очень примитивно сделано.

Аватар пользователя Ильич Рамирес Санчес Ильич Рамирес Санчес 20 июля 2008 в 15:36

жесть. а посмотреть документацию, cache.inc на тему cache_page и bootstrap.inc же на тему подмены и на уровне cache_page - складывать в файлы? заодно там чистку.

Посмотрите мой блог - увидите решения Smile

11 * * * * find /tmp/cache/ -mmin 15 -delete - это жестоко несколько, не находите? Smile

Аватар пользователя larin larin 20 июля 2008 в 23:07

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

Find отрабатывает намного быстрее, чем cron.php, и ресурсов не жрёт. Можно вместо него tmpwatch использовать, если он есть в системе.

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

Аватар пользователя Sky Cat Sky Cat 26 июля 2008 в 3:10

Quote:
3. Кэшируем только анонимов. Если им разрешены постинги - будут проблемы.

А какие именно могут проблемы возникнуть? Свои собственные посты не увидят или что-то похуже?
А можно ли сделать кэш для зарегистрированных пользователей тоже?
Заранее спасибо за ответ.

Аватар пользователя larin larin 26 июля 2008 в 4:10

Именно что не увидят свои посты. И не только свои. Все свежие (моложе времени кэша)
Если разрешать кэш для залониненных пользователей, то надо как-то такие ситуации отслеживать. Добавлять сброс при появлении новых нод, комментов и при изменении нод. Учитывать алиасы. Сделать можно, но не слышал, чтоб кто-нибудь брался. Работы много, толку мало.
Еще у пользователей бывают разные роли. Разным ролям показывают разный контент.
Ещё бывают блоки, типа лички, которые для всех уникальны. И, скажем, на Либрусеке, блок личных сообщений показывается на большинстве страниц.
А если все зарегистрированные пользователи видят одно и тоже, то в чём смысл регистрации?

Аватар пользователя kiev1 kiev1 26 июля 2008 в 9:45

find /tmp/cache/ -mmin 15 -delete
))) что это за кеш который сам сбрасывается? в случае большого количества страниц он будет просто мешать а не помогать так как вероятность и частота запроса определенной страницы уменьшается пропорционально их количеству, и когда работа сайта зависит от количества страниц - то это не правильный сайт

Аватар пользователя andypost@drupal.org andypost@drupal.org 26 июля 2008 в 14:38

Топик стартеру: копать в сторону drupal_bootstrap в фазе DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE там есть page_cache_fastpath()
Посмотрите также cacherouter для 6й версии - там есть кеш на файлах!
Ну и перед записью в файл его неплохо было бы блокировать...