mFilter 1.4.0 - перестроенная система кеширования
Ранее я опубликовал демо-сайт https://minishop3.ru/ с огромным каталогом — 200 000 товаров. Система прогрева кэша, на которую я делал ставку, на таком объёме показала себя плохо: первая загрузка после сброса кэша по-прежнему была долгой, прогрев занимал десятки минут, а синхронизация с реальностью требовала постоянной возни. Поэтому в 1.4 я полностью сменил архитектурный подход — заменил многоуровневое кэширование на простой денормализованный индекс. Каталог теперь не летает, но загружается и фильтруется с приемлемой скоростью на любом размере.
Замерял на каталоге 30 000 товаров с пятью фильтрами. До 1.4.0:
Стартовая точка осталась прежней: создаём набор фильтров в админке, добавляем туда свойства (опции MS3, TV, поля msProductData), привязываем к страницам каталога. Здесь ничего не поменялось — старые наборы продолжают работать без переделок.
Что добавилось — при сохранении набора система сразу инкрементально перестраивает индекс по тем ключам, которые менялись. Добавили новый фильтр weight — пересобирается только weight, остальные не трогаются. На 30k товарах это занимает 1–3 секунды, на 200k — около 10–15.
Главное изменение — две новые таблицы: mfl_facet_index_text для текстовых значений (бренды, цвета, размеры) и mfl_facet_index_num для числовых (price, weight). Структура максимально простая:
Вместо десятка отдельных SQL под каждый фильтр на странице — один batch-запрос забирает значения сразу для всех текстовых фильтров через GROUP BY (filter_key, filter_value). Чем больше фильтров на странице — тем заметнее выигрыш.
Денормализация всегда упирается в синхронизацию: данные теперь в двух местах, надо следить, чтобы они не разъезжались. Три слоя автоматики покрывают типичные пути правок каталога.
На действующих установках mFilter после апдейта на 1.4 ничего ломаться не должно. При установке пакета резолвер ставит задачу пересборки индекса в очередь Scheduler. Пока задача не отработала, фильтрация продолжает работать через fallback на исходные таблицы — медленнее, но без даунтайма. Когда индекс собрался — обработчики автоматически переключаются на чтение из него.
Если Scheduler не установлен — в шапке админки горит жёлтая кнопка «Построить индекс». Одно нажатие, и сайт ускоряется в 5–10 раз.
Старая вкладка «Прогрев кэша» переехала в сворачиваемый блок с пометкой Legacy. Вместо неё — обновлённая вкладка Обслуживание с тремя карточками:
Подсистема прогрева не выпилена — она ещё нужна для прогрева списков baseIds в AJAX-режиме. Но основная нагрузка (вычисление значений фильтров и фасетных счётчиков) теперь закрыта индексом, и прогрев перестал быть обязательным даже на больших каталогах. Соответствующая Scheduler-задача mfl_warmup продолжает работать раз в 50 минут — без неё AJAX-первый-запрос будет чуть дольше, но ничего не сломается.
Что изменилось по цифрам
Замерял на каталоге 30 000 товаров с пятью фильтрами. До 1.4.0:
- Применение фильтра — около 30 секунд на холодном кэше
- Расчёт suggestion'ов (количества товаров для каждого значения) — сотни миллисекунд на каждый фильтр
- На каталогах 200k+ цифры вырастали в разы, и прогрев был фактически обязателен, но всё равно не спасал
- Применение фильтра — 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 товара
Вместо десятка отдельных 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). На простаивающем сайте задача отрабатывает за миллисекунды и в логе ничего не пишет.
Бесшовное обновление
На действующих установках 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 отдаёт состояние индекса для интеграций и мониторинга
Ссылки
Поблагодарить автора
Отправить деньги
0