Fi1osof 15 августа 2013 1 4
Кстати, только сейчас заметил… Вот мы выполняем наши чанки и сниппеты через Smarty-теги, и радуемся тому, что в кеше страницы уже конечный HTML. НО, как оказалось, выполняемые сниппеты и чанки со всем своим хламом все равно попадают в кеш страницы, просто в другие элементы кеш-массива. Итог: полезный HTML страницы — 700 строк (на своем примере беру), а плюс к нему еще 4000 строк всякого хлама. Вот спрашивается «и нафига оно там мне надо». Особо обращаю внимание на то, что это индивидуальный кеш каждой страницы в отдельности, а не какой-то общий кеш. То есть на 100 страниц на весь их полезный HTML в кеше, я буду иметь еще в 6 раз больше кеша всякого хлама.

В чем тут соль? Дело в том, что конечный контент на вывод — это кеш-элементе _content. Но есть еще элемент sourceCache. Вот в него и набиваются все наши чанки, сниппеты и т.п. Меня все это еще больше удивляет в том плане, что тот же код сниппетов совершенно бессмысленный там (лично на мой взгляд). Ведь сниппеты не выполняются через EVAL (как это было в MODX Evolution), теперь сниппеты на выходе — это функции, находящиеся в отдельных файлах. Так вот, если это функция в отдельном файле, нафига мне ее код в кеше страницы? Ведь бывают очень даже не маленькие сниппеты (далее в статье я это докажу).

Так как же они туда попадают? Логично было копать через метод modX::runProcessor(). А он меня привел к нашему любимому MODX-парсеру, в частности к методу modParser::getElement(). Смотрим:
public function getElement($class, $name) {
    $realname = $this->realname($name);
    if (array_key_exists($class, $this->modx->sourceCache) && array_key_exists($realname, $this->modx->sourceCache[$class])) {
        /** @var modElement $element */
        $element = $this->modx->newObject($class);
        $element->fromArray($this->modx->sourceCache[$class][$realname]['fields'], '', true, true);
        $element->setPolicies($this->modx->sourceCache[$class][$realname]['policies']);

        if (!empty($this->modx->sourceCache[$class][$realname]['source'])) {
            if (!empty($this->modx->sourceCache[$class][$realname]['source']['class_key'])) {
                $sourceClassKey = $this->modx->sourceCache[$class][$realname]['source']['class_key'];
                $this->modx->loadClass('sources.modMediaSource');
                /* @var modMediaSource $source */
                $source = $this->modx->newObject($sourceClassKey);
                $source->fromArray($this->modx->sourceCache[$class][$realname]['source'],'',true,true);
                $element->addOne($source,'Source');
            }
        }
    } else {
        /** @var modElement $element */
        $element = $this->modx->getObjectGraph($class,array('Source' => array()),array('name' => $realname), true);
        if ($element && array_key_exists($class, $this->modx->sourceCache)) {
            $this->modx->sourceCache[$class][$realname] = array(
                'fields' => $element->toArray(),
                'policies' => $element->getPolicies(),
                'source' => $element->Source ? $element->Source->toArray() : array(),
            );
        }
    }
    if ($element instanceof modElement) {
        $element->set('name', $name);
    }
    return $element;
}


Вот как раз здесь мы и видим, как этот кеш устанавливается. $this->modx->sourceCache[$class][$realname] =
Конечно, здесь еще нет сохранения (кеш сохраняется уже после окончательного рендерера страницы, но именно этот элемент и попадает в общий кеш страницы).

Вот к примеру, я взял и урезал часть этого кеша:
$fields = $element->toArray();
unset($fields['snippet']);
unset($fields['content']);
$this->modx->sourceCache[$class][$realname] = array(
    'fields' => $fields,
    'policies' => $element->getPolicies(),
    'source' => $element->Source ? $element->Source->toArray() : array(),
);

То есть я из всего массива элемента удалил его исходные коды и все. Сохранил, обновил — сайт как работал, так и работает. Потому что как я и говорил выше, те же сниппеты находятся в отдельных файлах.
Вот это уже сократило кеш-файл с 4700 строк до 2500 строк.

Но я попробовал и еще более радикальный шаг — удалил вообще все, оставив только id-шник элемента. Единственное что я заметил из того, что слетело — параметр RAND некорректно Wayfinder-ом обработался (читай запрос сломался). Но во-первых, это лечится (есть процессор-замена Wayfinder-у), а во-вторых, кеш сократился до 900 строк.

Может, конечно, я и утрирую немного, может оно особо и не влияет на производительность (хотя помимо производительности ведь еще и другие вопросы есть. К примеру общий объем кеша. В моем случае после этих мелких правок он сократился с 201Кб до 46 Кб. То есть выигрыш 150 метров на 1000 документов), но все равно, я думаю, это можно было бы сделать и более экономно. Да, я понимаю, что какие-то элементы могут несколько раз на странице быть вызваны за один раз, но можно разделить же кешируемые на некешируемые. Если не было некешируемого скрипта (если все они или он кешируемый)… Нет, пишу, и понимаю, что все запущено, что все не так… У нас рекурсии, глобальные плейсхолдеры и т.д. и т.п. Вот чесслово, все это на мой взгляд так противоречит базовым принципам php-программирования (в плане областей видимости и т.п.). Из-за этих вложенных элементов (что теги могут быть внутри других тегов, и какие-то из них могут быть не кешируемыми и т.д. и т.п.), из-за этой рекурсии на выполнение (выполненный тег может вернуть другой тег, который в свою очередь тоже будет выполнен, а не просто как текст воспринят), все это дает маленький выигрыш в простоте, но дает бешенные сложности в плане организации кеша и оптимизации в принципе. В том же Smarty нет такой рекурсии (что выполни какой-то шаблон, получи код, обработай его опять, если найдешь в полученном коде Smarty-теги и т.п.), но это никак не мешает программировать сайт. Логика — в процессорах (и там рекурсия есть, если надо), представление — отдельно (в смарти-шаблоне). Но зато полное управление кешем. А здесь…

Давным-давно меня Райн спросил «а что ты не возьмешь отдельно xPDO, Smarty и не сделаешь свой движок?». Но он сам и ответил улыбаясь «TV-параметры, ACL, гибкая админка и т.п.». Да, это то, что мне очень нравится в MODX-е. Но вот над работой фронт-энда еще работать и работать. Я еще одно исследование еще не опубликовал (более обстоятельное), я его просто еще не закончил. Но оно меня, честно сказать, совсем пока не радует результатами…
Нет, я не планирую соскакивать, я думаю, мы постоянно развиваем MODX и он будет более производительный и т.п., но все равно иногда очень не весело.

Блин, хотел исследование написать, а получился какой-то крик души… Вот так всегда получается, когда начинаешь писать топик еще на уровне зацепки (чтобы описать все, каждый шаг, чтобы ничего не забыть и не переврать), а в процессе получаешь такие результаты и такие выводы делаешь, которые вообще не ожидал…
4 комментария
s
sasha-freez 15 августа 2013г в 13:31 #
Смотрю за тобой уже давно и смотрю сколько полезных и интересных статей написал)
Сам делаю сайты на MODX REVO, больше front-end разработчик.
Так вот, руки опускаются, когда понимаю, что в модх большая проблема с кэшем.
Добавляешь новую страницу в админку, почисти весь кэш, а если 5000 ресурсов тогда сколько ресурсозатрат будет.
Нет, для простых сайтов визиток и корпоративных сайтов проблем не возникает, но хочется сделать нечто больше по количеству страниц.
И тут понимаю, что встречаю вилы. Система самому нравится, за гибкость в работе верстальщика, в отличие от других систем.
Защищенность, сколько не работаю с модх — ломают очень редко в отличии от кривой джумблы и дырявого вордпресса.

Так вот для кэша ставил специальный плагин, который при добавлении страницы не очищал весь кэш, потом ставил кэш обновлялку.
Пробовал этот метод:
modx.im/blog/addons/663.html — кстати очень понравился в плане скорости, но есть ряд ограничений.
Но это же костыли(,

Интересно разработчики в modx3 сделают нормальную систему кэширования и более гибкую админку + возможность легкого создания пользовательских таблиц.
Fi1osof1
Fi1osof 15 августа 2013г в 19:54 #
В принципе, если сайт планируется большой, и предполагается большое количество кеш-файлов, то почти на 100% спасает переход на мемори-кеш-провайдер (memcache или APC). Ведь сам по себе большой общий кеш не страшен, а вот сброс его, это да, сервер сделает плакать, когда там десятки тысяч файлов. А на memcache или APC сброс почти мгновенный. Так же частенько использую заплатку cacheOptimizer. Когда страниц много и кеш-карта ресурсов разрастается (а так же начинает жутко тормозить на редактировании документов и сбросе кеша, так как MODX каждый раз запрашивает из базы данных все ресурсы и набивает их в в кеш контекста), тоже очень здорово помогает (отключает карту ресурсов полностью, и тогда на нее вообще нет запросов). Правда само собой MODX-у приходится запрашиваемую страницу искать в базе данных, но по моему опыту с магазином на 150 000+ товаров, что я сейчас делаю — это вообще не проблема.

Резюме: даже сейчас MODX все равно позволяет делать сайты с загрузкой не более 0,4 сек (для большого сайта можно сказать со скрипом, что это нормально).
А в новой версии MODX-а нас действительно ждут улучшения. И они даже не с самого MODX-а ожидаются, а больше с xPDO новой версии. Там Джейсон обещает более скоростную работу. Принцип работы xPDO поменяется, новые технологии применятся, автозагрузка и т.п. У него уже сейччас есть серьезные наработки и он очень доволен результатом.
den991
den99 16 августа 2013г в 03:46 #
Вот по этому пунктку, плиз, подробнее.
А в новой версии MODX-а нас действительно ждут улучшения.

Собственно
1. когда,
2. что изменится,
3. будет ли обратная поддержка старых сайтов (то есть обновление убьет сайт и его придется переписывать)
?
Fi1osof1
Fi1osof 16 августа 2013г в 04:55 #
А вот это только когда выйдет. Сейчас нет четкой информации и нет даже четкого релиза. Так что все ждем с закрытыми глазами.
Авторизуйтесь или зарегистрируйтесь (можно через соцсети ), чтобы оставлять комментарии.