Всем привет! Давненько я ничего не писал. Да особо уже ничего интересного о MODX рассказать и нечего. Но неожиданно появилась причина достать свой обгрызанный карандаш и поделиться с сообществом своим открытием. Дальше я расскажу о технических вещах, требующих определенных знаний и навыков в области программирования и MODX. Речь пойдёт о всем известном «must have» компоненте pdoTools.

У нас в компании осталось несколько сайтов на MODX, которые активно переводятся на другие платформы. Один из сайтов с более менее высокой посещаемостью. И пока он готовится к переезду на Laravel, мы решили его оптимизировать, чтобы сократить количество запросов в БД и снизить объём потребляемой памяти. И в процессе оптимизации мы обнаружили пару интересных вещей, дающих скрытый оверхед, которые можно охарактеризовать фразой «никто и подумать бы не мог».

Проблема 1

Первое, с чем мы столкнулись — использование в шаблонах и чанках конструкции Fenom $_modx->resource. Странным образом она давала много дополнительных запросов в БД. Казалось бы, что тут может грузить сервер? Пришлось погружаться в код. Всё оказалось просто — сайт достаточно большой и сложный, страницы имеют большое количество ТВшек. И pdoTools в целях оптимизации делает определенные манипуляции — он кэширует текущий ресурс в свой внутренний кэш — store, чтобы быстро обрабатывать конструкции типа

$_modx->resource.{свойство или ТВ}

И если свойство ресурса получить достаточно просто через $resource->toArray(), то ТВшку так получить не получится (вернее получится, но только простую). Поэтому её нужно получить через специальный метод класса ресурса getTVValue(), который как раз и генерирует запрос в БД. Эта обработка ТВ нужна, чтобы привести значение согласно указанному типу вывода, произвести дополнительные манипуляции, а также, если что, установить значение по-умолчанию.

У нас на основных страницах очень много ТВшек. Соответственно мы получаем значительное повышение количества SQL запросов единоразово. И всё ещё немного усугубляется тем, что у ресурсов есть неиспользуемые ТВшки (поленились убрать или просто временно не используются), которые также обрабатываются.

У стандартного парсера MODX этот момент реализован по другому — он обрабатывает ТВ, только когда она указана на странице. Указали одну, например [[*some_tv]], только её парсер и обработает. И будет только +1 sql запрос. Плюс она кэшируется на странице, в отличие от реализации на Fenom, что обнуляет лишний запрос при последующих загрузках страницы. А pdoTools на каждый запрос страницы принудительно запускает обработку всех ТВшек страницы.

Какие есть варианты решений? Первый вариант — сделать ленивую загрузку ТВ как в стандартном парсере MODX. Это уберёт обработку неиспользуемых ТВшек. Второй вариант — дополнить первый вариант сохранением обработанных ТВшек в кэш страницы. Третий вариант — добавить модификатор, который должен запускать обработку ТВ. Без него выводить необработанное значение. Так как большинство ТВшек скалярные, то их обрабатывать не нужно. Даже MIGX не требует обработки.

Проблема 2

Вторая проблема вытекает из первой. Не все знают, что на странице используется несколько экземпляров pdoTools. Первый экземпляр инициализируется в pdoParser. Он же и используется парсером. Он же и сохраняет в свой store все необходимые данные (поля ресурса вместе с ТВшками (как описано выше), другие ресурсы, к которым есть обращение на странице). Но как только вы вызываете на странице сниппеты pdoTools или свои сниппеты, которые внутри себя подключают pdoTools через $modx->getService('pdoTools'), вы опять с удивлением наблюдаете прирост SQL запросов при обращении к массиву $_modx->resource или к постороннему ресурсу по id, который раньше уже вызывался на странице и вроде бы должен был сохраниться в store. Всё это в store конечно есть, но только не в текущем экземпляре pdoTools, а в экземпляре, который находится в pdoParser.

Попробую визуализировать процесс. Представьте шаблон. В нем HTML разметка, теги Fenom — поля ресурса, ТВ, настройки, чанки и т.п. Ну и в середине вызов сниппета (pdoTools или собственной разработки, подключающий pdoTools), который внутри работает с чанками (это важно!).

Fenom работает с таким шаблоном последовательно — начинает парсить его сверху вниз с помощью парсера pdoParser, у которого внутри подключен pdoTools. При инициализации pdoTools подключает пользовательские модификаторы Fenom через событие pdoToolsOnFenomInit. При парсинге шаблона он кэширует поля ресурса, ТВ и т.д. Это как бы первый уровень.

Потом очередь доходит до сниппета. И pdoTools его запускает. А внутри сниппета инициализируется ещё один экземпляр pdoTools через $modx->getService('pdoTools'). Он пустой. И если внутри сниппета вызывается обработка чанка через getChunk($tpl), то запускается инициализация нового объекта Fenom с повторным запуском события pdoToolsOnFenomInit (в него тоже нужно добавить свои модификаторы). Это второй уровень парсинга. И встречая обращение к полю ресурса, ТВ или другому ресурсу, pdoTools заново начинает посылать запросы в БД, ведь у него store пустой.

Таким образом получается как минимум задвоение запросов. А если в сниппете создавать объект pdoTools через конструкцию new pdoTools (pdoTools сниппеты), то получите ещё один дубль.

Как можно выкрутиться в этом случае? Если вы используете сниппеты pdoTools, то тут поможет только рефакторинг сниппетов. Некоторые из них создают свои экземпляры pdoTools. Плюс другие тонкости с пробросом параметров. В общем, такой рефакторинг под силу не всем.

А если пишете свои, то используйте pdoTools из парсера

$pdoTools = $modx->getParser()->pdoTools

Ещё один лайфхак — это использовать сниппеты только для вывода данных, а в шаблоне уже работать с ними. Т.е. на первом уровне.

Важно!

Это рекомендации, а не универсальное решение. В большинстве случаев, как нам, они могут помочь. Но надо учитывать специфику и понимать, что вы делаете.

Заключение

Ну и под конец приведу пример результата оптимизации. На одной из страниц количество SQL запросов снизилось со 120 до 40. А если учесть, что у нас миллионы посещений в месяц, то можно с уверенностью сказать, что такая оптимизация прилично разгрузит SQL сервер и положительно скажется на скорости отдачи страниц. Что повышает конверсию и настроение у бизнеса :)

0   1405

Комментарии ()

    Вы должны авторизоваться, чтобы оставлять комментарии.

    Выделите опечатку и нажмите Ctrl + Enter, чтобы отправить сообщение об ошибке.