mFilter 1.4.0 - перестроенная система кеширования

Ранее я опубликовал демо-сайт https://minishop3.ru/ с огромным каталогом — 200 000 товаров. Система прогрева кэша, на которую я делал ставку, на таком объёме показала себя плохо: первая загрузка после сброса кэша по-прежнему была долгой, прогрев занимал десятки минут, а синхронизация с реальностью требовала постоянной возни. Поэтому в 1.4 я полностью сменил архитектурный подход — заменил многоуровневое кэширование на простой денормализованный индекс. Каталог теперь не летает, но загружается и фильтруется с приемлемой скоростью на любом размере.



Что изменилось по цифрам



Замерял на каталоге 30 000 товаров с пятью фильтрами. До 1.4.0:

  • Применение фильтра — около 30 секунд на холодном кэше
  • Расчёт suggestion'ов (количества товаров для каждого значения) — сотни миллисекунд на каждый фильтр
  • На каталогах 200k+ цифры вырастали в разы, и прогрев был фактически обязателен, но всё равно не спасал
После 1.4.0:

  • Применение фильтра — 1.7 секунды
  • Suggestion'ы — единицы миллисекунд
  • Каталоги 200k+ работают без прогрева (если не считать дублирования информации в нормализованной таблице)

Наборы фильтров



Стартовая точка осталась прежней: создаём набор фильтров в админке, добавляем туда свойства (опции MS3, TV, поля msProductData), привязываем к страницам каталога. Здесь ничего не поменялось — старые наборы продолжают работать без переделок.

Что добавилось — при сохранении набора система сразу инкрементально перестраивает индекс по тем ключам, которые менялись. Добавили новый фильтр weight — пересобирается только weight, остальные не трогаются. На 30k товарах это занимает 1–3 секунды, на 200k — около 10–15.

Денормализованный индекс



Главное изменение — две новые таблицы: mfl_facet_index_text для текстовых значений (бренды, цвета, размеры) и mfl_facet_index_num для числовых (price, weight). Структура максимально простая:

  • filter_key — ключ фильтра
  • filter_value — значение
  • product_id — ID товара
Покрывающий PRIMARY KEY по этим трём колонкам — и весь зоопарк JOIN'ов к msProductData / msProductOption / modTemplateVarResource заменяется одним сканом индекса с GROUP BY. Оптимизатор MySQL такой запрос пережёвывает за миллисекунды независимо от размера каталога.

Вместо десятка отдельных SQL под каждый фильтр на странице — один batch-запрос забирает значения сразу для всех текстовых фильтров через GROUP BY (filter_key, filter_value). Чем больше фильтров на странице — тем заметнее выигрыш.

Как индекс остаётся актуальным



Денормализация всегда упирается в синхронизацию: данные теперь в двух местах, надо следить, чтобы они не разъезжались. Три слоя автоматики покрывают типичные пути правок каталога.

  • Сохранение и удаление товаров через админку — плагин на OnDocFormSave / OnResourceDelete сразу обновляет индекс для затронутого товара. Стоит 5–20 мс на товар, незаметно для UX. Если установлен MS3 — фильтр по class_key пропускает сохранения статических страниц.
  • CSV-импорт через MS3 ImportCSV — после события msOnAfterImport автоматически запускается полная пересборка. На крупных каталогах уходит в очередь Scheduler, чтобы не блокировать ответ админ-импорта.
  • Программные правки через $resource->save() и SQL-импорты — догоняет Scheduler-задача mfl_sync_facet_index, recurring каждые 5 минут. Находит товары, у которых editedon позже последней синхронизации, и пересобирает индекс точечно для них (батчами по 5000 ID). На простаивающем сайте задача отрабатывает за миллисекунды и в логе ничего не пишет.
На случай совсем нештатных сценариев (прямой SQL без editedon=NOW(), DELETE через консоль БД) остаётся ручной запуск — кнопка «Переиндексация» в шапке админки или Scheduler-задача mfl_rebuild_facet_index для полной пересборки в фоне.

Бесшовное обновление



На действующих установках mFilter после апдейта на 1.4 ничего ломаться не должно. При установке пакета резолвер ставит задачу пересборки индекса в очередь Scheduler. Пока задача не отработала, фильтрация продолжает работать через fallback на исходные таблицы — медленнее, но без даунтайма. Когда индекс собрался — обработчики автоматически переключаются на чтение из него.

Если Scheduler не установлен — в шапке админки горит жёлтая кнопка «Построить индекс». Одно нажатие, и сайт ускоряется в 5–10 раз.

Вкладка «Обслуживание»



Старая вкладка «Прогрев кэша» переехала в сворачиваемый блок с пометкой Legacy. Вместо неё — обновлённая вкладка Обслуживание с тремя карточками:

  • Индекс фасетов — статус (активен / в очереди / не построен), количество текстовых и числовых записей, время последней пересборки, две кнопки запуска (синхронно или через Scheduler)
  • Кэш данных фильтров — счётчик записей и кнопка «Очистить»
  • Прогрев baseIds — старая вкладка прогрева, теперь свёрнутая. Используется только для AJAX-режима, после стабилизации индекса будет удалена

Что осталось от прогрева



Подсистема прогрева не выпилена — она ещё нужна для прогрева списков baseIds в AJAX-режиме. Но основная нагрузка (вычисление значений фильтров и фасетных счётчиков) теперь закрыта индексом, и прогрев перестал быть обязательным даже на больших каталогах. Соответствующая Scheduler-задача mfl_warmup продолжает работать раз в 50 минут — без неё AJAX-первый-запрос будет чуть дольше, но ничего не сломается.

Прочие изменения в 1.4



  • Единая кнопка «Переиндексация» в шапке вместо нескольких разрозненных — запускает алиасы + индекс одной операцией
  • Filter::applyToIds для внешних ID-списков перешёл на raw PDO fetch — экономит 2–3 секунды на выборках 30k+ строк
  • Новая Scheduler-задача mfl_cleanup_request_ids — подчищает stale-данные временных таблиц после fatal-обрывов PHP
  • Новая Scheduler-задача mfl_sync_facet_index — recurring sync индекса по editedon
  • Эндпойнт /maintenance/status отдаёт состояние индекса для интеграций и мониторинга

Ссылки



Николай Савин
3 часа назад
modx.pro
18
+1
Поблагодарить автора Отправить деньги

Комментарии: 0

Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
0