vgrish
24 авг. 2013 г., 19:54

сохранить документ в кеш memcache

Суть идеи такова: сохранить ресурс в виде html странички в кеш memcache средставами MODX (плагином), посредством nginx прочитать ресурс из кеша, так сказать минуя MODX… Плюсы — nginx отдает страничку практически мгновенно, сервер не тратит ресурсы…
нам нужно два события — OnSiteRefresh и OnBeforeSaveWebPageCache. По первому событию чистить кеш, по второму сохранить ресурс в кеш. скелет плагина:
switch ($modx->event->name) { case 'OnSiteRefresh': //чистим кеш break; case 'OnBeforeSaveWebPageCache': if ($modx->resource->get('cacheable') && $modx->resource->get('published') && $modx->resource->_output != '') { $memcache = new Memcache; $memcache->connect('localhost', 11211); $expire = 50;//время хранения 50с $uri = $modx->resource->get('uri'); $context = $modx->context->get('key'); $key = "$context/$uri"; $output = &$modx->resource->_output; $time = time(); $cacheArray = array('output'=>$output, 'time'=>$time); $tmp_object = $output; $memcache->set($key, $tmp_object, false, $expire); $memcache->close(); break; } }
запись в кеш
$memcache = new Memcache; $memcache->connect('localhost', 11211);//подключаемся к memcache $expire = 50;//время хранения 5с кеша $tmp = "<h1>привет</h1>"; $memcache->set('key', $tmp, false, $expire);//записываем по ключу значение в кеш $memcache->close();//закрываем подключение
получить значение (страничку) из кеша пока на время проб, просто снипетом
$memcache = new Memcache; $memcache->connect('localhost', 11211) or die ("Не могу подключиться"); $get_result = $memcache->get('key'); echo "Данные из кеша:".$get_result." \n"; $memcache->close();
ключ формировать по следующему шаблону: site_name:context:uri время хранения кеша пока не знаю, возможно алгоритм какой нибудь придумать, пока можно выставить ручками
p.s. хотел донести до вас основную мысль, интересно выслушать ваше мнение… я не программист и возможно это вообще бредовая идея… Жду ваши коментарии…
ну и вот первый вопрос ) как получить страничку в html после обработки парсером всех чанков и других тегов… и затем сохранить ее в переменную?
$output = &$modx->resource->_output; $time = time(); $cacheArray = array('output'=>$output, 'time'=>$time); $tmp_object = $output;
да и насчет OnBeforeSaveWebPageCache неправильно думаю, оно срабатывает только когда ресурс сохраняем… какое событие сюда лучше подойдет?
не чет не то…
А зачем отдельная инициализация мемкеша? Он же в составе MODX-а идет. По умолчанию в настройках MODX-а указано cache_handler=xPDOFileCache, то есть используется файловый кеш-провайдер. Поменяй на cache.xPDOMemCached и все. Кеширование будет на мемкеше. И в плагине спокойно сможешь использовать $modx->cacheManager->set($key, $value); Плюс к этому при сбросе кеша сайта MODX и твой пользовательский кеш будет очищать, не надо ничего дописывать.
А что тебя не устраивает? Наоборот правильное событие. Если документ кешируемый и не был еще закеширован, тогда этот плагин и сработает. А если уже закеширован, то у тебя nginx будет отдавать страницу и все.
Пожалуй, я тоже сейчас попробую это сделать, давно хотел.
Кстати, имей ввиду, что еще в мемкеш можно объекты сохранять. Только там есть тонкости. Нельзя туда сохранить, к примеру, дескриптор соединения с базой данных. Есть в общем ООП-шные методы __sleep() и __wakeup(). __sleep() сработает прям перед сохранением (автоматически). В нем можно будет удалить переменные $modx и т.п., а __wakeup() сработает автоматически, когда будешь получать объект из кеша (в этот момент ему можно будет опять присвоить $modx). Тоже может пригодиться для тюннинга.
да я пока на файловый перешел, чтоб только плагин мне тут мусорил…
Кстати, ты memcache ведь используешь? А почему не memcached? Вот сравнительная статья.
ну событие сработает один раз когда документ сохраняем, потом из memcache кеш уйдет и тю тю… кеша нет
Поменяй на xPDOMemCached и все.
Поправочка — cache.xPDOMemCached
И еще момент: чтобы сразу есть настройки, которые необходимо и в сам конфиг-файл переносить. Дело в том, что для чтения системных настроек из базы данных требуется инициализация самого MODX-а. Это звучит очень логично, но не все на этом внимание заостряют. Так вот, инициализация требует предварительного чтения конфигов. И вот что получается — пока MODX не получил данные из базы данных, он использует конфиги файловые, в том числе и значения по умолчанию. А так как настройка cache_handler=cache.xPDOMemCached хранится в базе данных, то в момент инициализации MODX еще ничего о ней не знает, и соответственно использует стандартный файловый кеш-провайдер. И получив настройки из БД, он только потом очухивается, и начинает использовать Memcached. Но до этого успевает записать конфиги в файлы, и вообще каждый раз при старте читает конфиги из файлов.
Вот чтобы этого не происходило и чтобы он сразу использовал Memcached, зайди в core/config/config.inc.php и в $config_options пропиши эту настройку тоже:
$config_options = array ( "cache_handler" => "cache.xPDOMemCached", );
Вот тогда он сразу будет мемкешед юзать.
незнаю, изначально как то только memcache на сервер ставил…
наверно лучше на OnWebPagePrerender — тогда кеш умер, страничку обновили и кеш снова есть
Ставь memcached. Не сложнее устанавливается. Конфиги его будут в /etc/memcached.conf (это если лимит памяти захочешь поднять).
Тоже логично. Хотя можно и мемкешу, и MODX-у задать одинаковое время жизни кеша. Тогда будет нормуль.
так ты мне обьясни в чем разница то? я вот пока не вижу разницы, так зачем на него переходить. что cache.xPDOMemCached, что cache.xPDOMemCache — по сути одно и тоже, разъве нет?
как обработанную страничку в кеш запихать в виде html? у меня что то пока не выходит…
значит как почистить чеш можно не волноваться, при OnSiteRefresh само все почистится, это уже хорошо)
Я же тебе выше дал ссылку на сравнительную статью. Давай я пересказом не буду заниматься, а ты прочитаешь и сам для себя решишь в чем разница и надо или не надо.
Щас сделаю и скажу.
ну я для себя сделал выводы что разницы никакой) Да и статья устарела, может сейчас что то и изменилось… позже покопаю… В данном вопросе это не столь важно.
В таком случае наверно лучше использовать OnWebPageComplete. Это самое последнее событие, и как видишь, без учета закеширован или нет.
public function _postProcess() { if ($this->resourceGenerated && $this->getOption('cache_resource', null, true)) { if (is_object($this->resource) && $this->resource instanceof modResource && $this->resource->get('id') && $this->resource->get('cacheable')) { $this->invokeEvent('OnBeforeSaveWebPageCache'); $this->cacheManager->generateResource($this->resource); } } $this->invokeEvent('OnWebPageComplete'); }
Черновой код плагина:
<?php switch($modx->event->name){ case 'OnWebPageComplete': $key = "resource/".$modx->resourceIdentifier; $output = & $modx->resource->_output; $modx->cacheManager->set($key, $output); break; default:; }
Но сейчас еще буду проверять насколько этот кеш годится. Ведь там php return. Скорее всего надо будет переопределять кеш-провайдер, чтобы сохранять чистый HTML.
так не пойдет, ты стандартно его засунул… тогда можно было вообще плагин не писать, а просто обработчик переключить на cache.xPDOMemCached, и уже nginx выбирать что modx стандартно кеширует!
переопределять? я смутно представляю что это… но я думаю логика такая — обработчик менять на файловый, получать страничку и запихивать уже в memcache
обработчик менять на файловый, получать страничку и запихивать уже в memcache
Нафига такой изврат? Зачем данные туда-сюда гонять?
Переопределять — это создать свой кеш-провайдер, расширяющий базовый, и туда добавить, к примеру, метод setPureCode() то есть сохранять как есть, а не совать в return;
и уже nginx выбирать что modx стандартно кеширует!
1. Стандартный кеш документа нафиг не нужен, потому что там много хлама. 2. Нгинкс не обрабатывает php.
ну все что ты сказал правильно, и я это вполне понимаю) Но вот выразился так кривовато, а как расширить и т.д. это вообще темный лес… Непростая задача наверное
Ты сможешь это сделать?
Судя по всему, ничего переопределять не понадобится. Я уже результат получил на уровне нгинкса. Сейчас последние штрихи в плагине делаю. Больше с правилами для нгинкса провозился, я же не сисадмин.
Ну все, я получил результат конечный. Было несколько подводных камней, так что оформлю в новый топик. Сегодня опубликую, но чуть позже.
Ок!) С нетерпением жду… Молодчик!
Пока топик пишу, погоняй: evropa-clinic.modxdev.webtm.ru Смотри в файрбаге время отклика при повторном заходе.
ну нормал 100 мс...))) ты только время кеша маленькое выставил… или еще делаешь что то… как интерпрайз летает)))
ну нормал 100 мс...)))
На самом деле меньше. У меня 70+- несколько мсек показывает. Из них минимум 40 — это пинг :-)
ты только время кеша маленькое выставил… или еще делаешь что то…
Вообще-то когда ты смотрел, лоэдимпакт в 50 клиентов фигачил по сайту)))
кинь тест глянуть. Нагрузку не мониторил в это время?
Тест не сохранил, так как бесплатный всегда хрень показывает. Показывал, что секунду с лишним ответ. Нагрузке на сервере вообще не ощущал.
А я пошел спать. Удачи
Кстати, стандартным $modx->cacheManager-ом кеш сохранял. Само собой мемовским. И все ОК, ничего лишнего не понадобилось делать.
Наверно надо пересмотреть формирование ключа. Много ограничений накладывается, в md5 нужно кодировать…
в плагине добавляем
$key = md5($key);
в конфиге nginx добавляем в секцию http
perl_set $md5_uri 'sub { use Digest::MD5 qw(md5_hex); my $r = shift; my $args=$r->args; return md5_hex($args); }';
в целом конфиг nginx в таком виде:
user nginx; worker_processes 1; worker_rlimit_nofile 100000; error_log /var/log/nginx/error.log; #error_log /var/log/nginx/error.log notice; #error_log /var/log/nginx/error.log info; pid /var/run/nginx.pid; events { worker_connections 1024; use epoll; } http { perl_set <strong>$md5_uri</strong> 'sub { use Digest::MD5 qw(md5_hex); my $r = shift; my $uri=$r->uri; my $args=$r->args; return md5_hex($args); }'; include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; client_max_body_size 100m; sendfile on; tcp_nopush on; tcp_nodelay on; server_tokens off; gzip on; gzip_static on; gzip_comp_level 5; gzip_min_length 1024; keepalive_timeout 65; gzip_proxied any; gzip_types text/plain text/html text/xml application/xml application/x-javascript text/javascript text/css text/json; gzip_disable "msie6"; charset utf-8; limit_conn_zone $binary_remote_addr zone=addr:10m; # Load config files from the /etc/nginx/conf.d directory include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*; }
ну и конфиг на сайт
upstream backend-test {server unix:/var/run/php5-test.sock;} server { listen 80; server_name test.ru; root /var/www/test/www; access_log /var/log/nginx/test-access.log; error_log /var/log/nginx/test-error.log; index index.php index.html; rewrite_log on; if ($host != 'test.ru' ) { rewrite ^/(.*)$ http://test.ru/$1 permanent; } location ~* ^/core/ { deny all; } location / { try_files $uri $uri/ @rewrite; } location @rewrite { rewrite ^/(.*)$ /index.php?q=$1; } location ~ \.php$ { default_type text/html; set $memcached_key "default/test_<strong>$md5_uri</strong>"; # где test_ это cache_prefix memcached_pass unix:///var/run/memcached/mem.socket; error_page 404 401 405 502 504 = @php; } location @php { include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_pass backend-test; } location ~* ^.+\.(jpg|jpeg|gif|css|png|js|ico|bmp)$ { access_log off; expires 10d; break; } location ~ /\.ht { deny all; } }
теперь плагин скидывает в кеш по ключу md5 — соответственно мы уходим от ограничения на длину ключа в 250 символов и по идее теперь не должно быть проблем с кириллицей в uri… p.s. должно работать, время будет проверю

Добавить комментарий