Эта тема уже не раз поднималась. Хочу поделится своим опытом оптимизации более менее высоко нагруженного сайта на MODX Revolution.

Статистика и цифры

Посещаемость ресурса (далее сайта), о котором идет речь, в сутки более 6 тысяч уникальных посетителей. В пики около 20 тысяч.

История

Изначально сайт работал на MODX Evolution с 2008 по 2013 года. В середине 2013 нужно было реализовать ещё один похожий сайт, но с некоторыми общими элементами. После некоторого раздумья решили оставить Evo в покое и сделать новый сайт на MODX Revolution. На это было несколько весомых причин:

  • Контексты(мультидоменность). Так как вместо одного сайта нужно делать два, но с общими элементами, то тут без контекстов в Revo не обойтись. В Evo такого функционала нет.
  • Регулярные обновления ядра. Evo заброшен официальными разработчиками и давно не обновляется. В Revo с этим проблем нет.

Разработка нового сайта

Большая часть функционала была реализована своими сниппетами или сниппетами-обертками готовых компонентов. Сниппеты приходилось вызывать некешируемыми, так как было много блоков, которые выводят рандомную информацию. В итоге среднее время генерации страницы было ~0.2-0.4. Но были и большие страницы, которые отдавались около секунды. Кто-то скажет что 0.3-0.4 это нормально, но нас это не устраивало. Посещаемый сайт должен работать гораздо быстрее.

Оптимизация

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

В шаблоне было примерно так:

<!DOCTYPE HTML>
<html>
<head>
<title>title</title>
</head>
<body>
[[!right_column]]
[[*content]]
</body>
</html>

А сниппет right_column выглядел примерно следующим образом:

[[!snippet1? &param1=`1` &param2=`2`]]
[[!snippet2? &param1=`1` &param2=`2`]]
[[!snippet3? &param1=`1` &param2=`2`]]
[[!snippet4? &param1=`1` &param2=`2`]]
[[!snippet5? &param1=`1` &param2=`2`]]

То есть парсеру MODX приходится трудится и обрабатывать вызовы вложенных сниппетов.

Попробовали переделать правую колонку полностью на php. Получилось что то вроде:

$output = '';
$output .= $modx->runSnippet('snippet1', array('param1' => 1, 'param2' => 1,));
$output .= $modx->runSnippet('snippet2', array('param1' => 1, 'param2' => 1,));

Но выигрыша это в скорости не особо дало. Тогда пошли другим путем и вынесли всю логику в один общий сниппет. Тогда разница была ощутима.

Идем дальше. Помните я говорил про рандомные блоки и что их нельзя кешировать?

Мы придумали другой способ кеширования.
Смысл такой: например нам нужно выводить 5 случайных статей из раздела «Статьи». Тогда получаем 5 статей запросом с сортировкой при помощи rand() и записываем эти 5 статей в кеш, например, на 5 минут. И при выводе перемешиваем их на php при помощи функции shuffle. Тогда запрос в бд будет всего один раз в 5 минут. А пользователь даже ничего не заподозрит, что меняются всего 5 элементов :)

Пример такого сниппета:

$cache_handler = $modx->getOption('cache_handler', null, 'xPDOFileCache');
$cache_lifelime = 300;
 
$cacheOptions = array(
    xPDO::OPT_CACHE_KEY => 'right_column',
    xPDO::OPT_CACHE_HANDLER => $cache_handler,
);
 
$items = array();
 
if(($results = $modx->cacheManager->get('articles' . $modx->context->key, $cacheOptions))){
    $items = $results;
}else{
 
    $query = $modx->newQuery('modResource')
        ->where(array('parent' => 1))
        ->select($modx->getSelectColumns('modResource', 'modResource', '', 
            array('id', 'uri', 'pagetitle', 'introtext'))
        )
        ->limit(5)
        ->sortby('rand()');
 
    if($query->prepare() && $query->stmt->execute()){
        if ($results = $query->stmt->fetchAll(PDO::FETCH_ASSOC)) {
            $items = $results;
        }
    }
 
    $modx->cacheManager->set('articles' . $modx->context->key, $items, 
        $cache_lifelime, $cacheOptions);
 
}
 
if(is_array($items) && !empty($items)){
    // работаем с массивом $items    
 
}

Ещё следует заметить, что хороший прирост в скорости дает отключение галочки «Статичный» у всех элементов(шаблоны, чанки, сниппеты...). Спасибо Евгению Борисову за ценную информацию о вредной статичности.

Итог

После проведения работ по оптимизации, скорость загрузки выросла до ~0.04-0.08.