MAATRIX / Блог / Magento Open Source: кэш протух, индексы встали — сценарий шестого месяца

Magento Open Source: кэш протух, индексы встали — сценарий шестого месяца

MAATRIX

Demo-каталог на 20 товаров ставится за час, магазин выглядит быстрым, все довольны. Реальная боль начинается на третий-шестой месяц, когда каталог разрастается до пары тысяч SKU, накопился трафик роботов и клиентов, и внезапно выясняется, что «быстрый» магазин тормозит на добавлении товара в корзину, а переиндексация каталога после массового обновления цен занимает не секунды, а десятки минут. Разберём, что именно ломается в self-hosted Magento Open Source после установки демо-магазина — и что с этим делать до того, как это стало пожаром.

Почему демо-установка не похожа на прод

Magento Open Source (бесплатная версия, на которой раньше строился Adobe Commerce и которая продолжает жить как community-edition) на этапе установки скрывает почти все свои будущие проблемы. Sample Data — это горстка товаров, пустая база сессий, холодный кэш, который прогревается за пару кликов, и индексы, которые пересчитываются за секунды, потому что считать почти нечего.

Реальность отличается по нескольким осям сразу:

  • Каталог растёт не линейно по нагрузке на индексацию — с ростом числа товаров, категорий и атрибутов время переиндексации растёт быстрее, чем количество SKU, из-за роста числа комбинаций (цена × склад × валюта × сайт × store view).
  • Сессии и корзины реальных покупателей — это постоянная запись в Redis или в файлы, а не редкие обращения тестового аккаунта.
  • Роботы (поисковые, парсеры цен, боты недобросовестных конкурентов) генерируют уникальные URL с параметрами фильтрации, которые демо-магазин никогда не видел — и именно они первыми обнажают дыры в стратегии кэширования.
  • Cron, на котором держится вся асинхронная часть Magento (индексация по расписанию, очистка сессий, email-очереди, sitemap), либо работает годами без присмотра, либо тихо умирает после одного упавшего задания — и это остаётся незамеченным месяцами.

Ничего из этого не проявляется в первую неделю. Проявляется на волне первого реального трафика — часто это распродажа, сезонный пик или просто органический рост каталога.

Кэш, который должен ускорять, а не мешать

У Magento Open Source два независимых уровня кэша, и путаница между ними — источник половины проблем «сайт то быстрый, то нет».

Layer 1 — внутренний кэш Magento (Redis или файлы). Это кэш конфигурации, layout, блоков, коллекций — то, что настраивается в app/etc/env.php в секции cache. По умолчанию после установки он может остаться на файловой системе, что на каталоге в несколько тысяч товаров и активной админке даёт заметную деградацию — диск с большим числом мелких файлов кэша плохо себя ведёт при параллельных запросах на VPS с обычным SSD, не говоря уже про сетевые диски. Перевод на Redis — не опция «для больших проектов», а базовая гигиена уже на среднем магазине:

'cache' => [
    'frontend' => [
        'default' => [
            'backend' => 'Cm_Cache_Backend_Redis',
            'backend_options' => [
                'server' => '127.0.0.1',
                'database' => 0,
                'port' => '6379',
            ],
        ],
        'page_cache' => [
            'backend' => 'Cm_Cache_Backend_Redis',
            'backend_options' => [
                'server' => '127.0.0.1',
                'database' => 1,
                'port' => '6379',
                'compress_data' => '1',
            ],
        ],
    ],
],

Обратите внимание на разные database для основного кэша и для Full Page Cache — если их не развести, инвалидация одного случайно задевает другой, и по логам это выглядит как необъяснимые скачки времени отклика. Если Redis для магазина ещё не разворачивали — есть отдельный разбор установки и настройки Redis на VPS.

Layer 2 — Full Page Cache (Varnish или встроенный built-in FPC). Встроенный кэш Magento неплох для старта, но он живёт внутри PHP-процесса и не спасает от нагрузки на PHP-FPM — запрос всё равно доходит до приложения, просто отдаёт готовую страницу без похода в базу. Varnish перед веб-сервером отдаёт HIT вообще без обращения к PHP, и именно поэтому Magento из коробки умеет генерировать VCL под Varnish (Stores → Configuration → Advanced → System → Full Page Cache, там же экспорт готового .vcl). На проекте с реальным трафиком переход с built-in FPC на Varnish — одно из немногих изменений, которое даёт ощутимую разницу без переписывания кода. Если Varnish в инфраструктуре ещё нет, общий принцип настройки (независимо от CMS) разобран в статье про ускорение сайта через Varnish Cache — с Magento логика та же, отличается только готовый VCL-шаблон и список заголовков, которые магазин использует для инвалидации.

Типичная грабля шестого месяца — кэш «протухает» не по времени (TTL Magento по умолчанию довольно долгий), а по событию: сохранение товара, изменение цены, обновление остатков должны триггерить точечную инвалидацию через X-Magento-Tags. Если кастомная логика (модуль скидок, интеграция с 1С, синхронизация остатков через API) не проставляет теги правильно — либо кэш не обновляется вовреме и покупатели видят старые цены, либо разработчик в панике добавляет cache:flush в каждый второй cron-скрипт, и тогда кэш обнуляется целиком по десять раз в час, что по эффекту равносильно его отсутствию.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать VPS

Переиндексация каталога: где растут расходы

Индексы Magento — это не индексы MySQL в привычном смысле, а отдельные плоские таблицы (catalog_product_index_price, catalog_category_product_index и другие), которые Magento пересчитывает из «сырых» данных для быстрой отдачи каталога и цен. Индексаторов несколько: цены, остатки, категории, полнотекстовый поиск, дизайн-конфигурации — каждый со своим объёмом работы.

Два режима на выбор:

  • Update on Save — индекс пересчитывается сразу при сохранении сущности. Удобно для разработки и маленьких каталогов, но на пару тысяч товаров сохранение одного товара с массовым назначением категорий может занимать секунды-десятки секунд, потому что пересчёт идёт синхронно в рамках того же запроса.
  • Update by Schedule — изменения складываются в очередь (catalog_url_rewrite, indexer_* changelog-таблицы), а cron пересчитывает партиями по расписанию. Это стандартный режим для прода, но именно он чаще всего ломается тихо: если cron не выполняется (упал systemd-таймер, PHP-процесс упёрся в memory_limit, изменился путь к PHP после обновления сервера), индексы просто не обновляются — сайт продолжает работать, но цены и остатки на витрине расходятся с админкой, и это может длиться днями до первой жалобы клиента.

Проверка состояния — первое, что стоит смотреть при подозрении на проблему:

bin/magento indexer:status

Статус invalid у любого индексатора — сигнал, что realtime-данные и то, что видит покупатель, разошлись. Полная переиндексация вручную:

bin/magento indexer:reindex

На каталоге в несколько десятков тысяч SKU полный reindex — это не операция «на всякий случай», а событие, которое стоит планировать: она грузит MySQL и Elasticsearch/OpenSearch одновременно, и на VPS с урезанным IOPS способна на время просадить отклик всего магазина. Отдельная грабля — таблица cron_schedule: без периодической очистки (schedule_lifetime в настройках cron) она разрастается до сотен тысяч строк за несколько месяцев активной работы, и каждый проход планировщика начинает тормозить сам по себе, что усугубляет опоздания индексации по цепочке.

Стек сервера, который реально нужен

На старте кажется, что Magento — это «PHP + MySQL, как любой сайт». В реальности минимальный рабочий комплект для Open Source последних 2.4.x веток выглядит так:

КомпонентРольПочему нельзя пропустить
PHP-FPM (8.x, конкретная поддерживаемая версия зависит от релиза Magento)Исполнение приложенияКаждый релиз Magento жёстко привязан к диапазону версий PHP — сюрприз всплывает при апгрейде ОС
MySQL или MariaDBОсновная база данныхКаталог, заказы, клиенты, конфигурация — всё здесь
Elasticsearch или OpenSearchПолнотекстовый поиск и часть индексации каталогаОбязателен начиная с определённых веток 2.4.x, встроенного MySQL-поиска для прода уже недостаточно
RedisКэш и/или сессииБез него — деградация под нагрузкой, см. раздел про кэш выше
Varnish (опционально, но по факту почти всегда)Full Page CacheРазгружает PHP-FPM от повторяющихся GET-запросов
Cron (systemd timer или классический crontab)Индексация, очереди, обслуживаниеБез него магазин «протухает» изнутри незаметно

Это не один процесс на VPS с 2 ГБ ОЗУ, а несколько сервисов, каждый со своим аппетитом к памяти: Elasticsearch/OpenSearch на JVM обычно просит от 1-2 ГБ heap уже на небольшом каталоге, MySQL — свой буферный пул под InnoDB, PHP-FPM — пул воркеров под конкурентный трафик, Redis держит в памяти сессии и кэш целиком. На практике для магазина с несколькими тысячами товаров и заметным трафиком закладывайте сервер, где под каждый сервис есть отдельный бюджет памяти, а не общий пул на остаточном принципе — иначе первым падает в OOM либо поисковый движок, либо PHP-FPM в момент пиковой нагрузки.

Elasticsearch/OpenSearch на том же сервере часто становится первой жертвой экономии на памяти, потому что визуально «магазин же работает», а деградация поиска и части индексации накапливается тихо. Если стек ещё не развёрнут, разумно сразу закладывать OpenSearch как более свежую линию (Elasticsearch после определённой версии лицензии ушёл в сторону, и часть self-hosted проектов мигрирует именно на OpenSearch) — установка описана в статье про установку и настройку OpenSearch на VPS.

Обновления между минорными версиями — не `apt upgrade`

На первый взгляд обновление Magento — это composer require magento/product-community-edition <версия> плюс bin/magento setup:upgrade. На практике даже минорный переход (например, внутри одной ветки 2.4.x) регулярно тянет за собой:

  1. Изменения в зависимостях composer. Magento завязан на конкретные версии десятков сторонних пакетов, и минорный апдейт ядра нередко требует поднять минимальную версию PHP-расширений или другого пакета — конфликтует с кастомными модулями, которые эти версии жёстко фиксируют.
  2. Изменения в схеме БД и переиндексация с нуля. setup:upgrade может добавлять таблицы, менять индексы MySQL, и после него часто требуется полный bin/magento indexer:reindex — на крупном каталоге это часы простоя витрины поиска и цен, если не подготовиться заранее.
  3. Несовместимость сторонних модулей и тем. Open Source живёт на экосистеме бесплатных и платных расширений с рынка, и далеко не все их авторы тестируют совместимость день в день с релизом ядра — приходится ждать патч или временно откатывать функциональность.
  4. Требование к версии PHP. Каждая крупная ветка Magento поддерживает свой диапазон версий PHP, и рано или поздно апгрейд ОС упирается в то, что текущая версия Magento формально не поддерживает свежий PHP — а старый PHP тем временем снимается с поддержки дистрибутивом. Общий принцип безопасного перехода между версиями PHP на проде разобран отдельно в статье про переход на новую версию PHP без падения — для Magento он важнее, чем для обычного PHP-проекта, из-за плотной завязки версий.

Рабочая практика, которая экономит нервы: обновления сначала на копии прода (staging с актуальным дампом БД и синхронизированными файлами), с фиксацией шагов миграции в виде скрипта, а не «по памяти». Откат без свежего бэкапа БД и файлов перед стартом апгрейда — плохая идея: часть миграций схемы необратима без восстановления из бэкапа.

Симптомы деградации на шестом месяце — как их узнать

Несколько сценариев, которые чаще всего всплывают именно после нескольких месяцев боевой эксплуатации, а не сразу:

  • Каталог отдаёт актуальные товары, а цены — вчерашние. Почти всегда это Update by Schedule плюс упавший или не запускавшийся cron. Первый шаг диагностики — bin/magento indexer:status и проверка последних записей в таблице cron_schedule (статус error — прямая улика).
  • Магазин резко тормозит после массового импорта товаров или цен. В режиме Update on Save импорт тысяч строк синхронно пересчитывает индексы на каждое изменение и фактически блокирует индексацию до конца операции. Решение — временно переключать индексацию в Update by Schedule на время импортов, либо запускать bin/magento indexer:reindex пакетно после, а не полагаться на автоматику построчно.
  • Память сервера стабильно растёт, пока не упрётся в своп. Частая причина — Redis без ограничения maxmemory и внятной maxmemory-policy, который копит сессии и кэш без вытеснения. Проверяется командой redis-cli info memory.
  • После деплоя обновления сайт отдаёт 500 или белый экран. Часто — забытый bin/magento setup:di:compile и cache:flush, либо права на var/cache, var/generation, pub/static после деплоя от другого пользователя, чем веб-сервер.
  • Поиск по каталогу находит не то или не находит вовсе. Признак рассинхронизации индекса полнотекстового поиска — обычно решается точечной переиндексацией catalogsearch_fulltext, но при повторе стоит проверить логи движка на нехватку памяти под JVM heap.

Ни один из этих симптомов не про то, что Magento «плохо написан» — это следствие того, что многослойная архитектура требует соответствующей операционной дисциплины: мониторинга cron, разделения кэшей, планового обслуживания индексов, а не разовой настройки «поставили и забыли».

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать VPS

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Magento Open Source вообще можно держать на VPS без выделенного сервера?

Можно, это обычный сценарий для небольших и средних каталогов — важно закладывать отдельные ресурсы под каждый компонент стека (PHP-FPM, MySQL, Elasticsearch/OpenSearch, Redis, опционально Varnish), а не рассчитывать на конфигурацию «для сайта на WordPress».

Без Varnish вообще никак? Built-in Full Page Cache не справится?

Справится на небольшом трафике. Built-in FPC снимает нагрузку с базы, но не с PHP-FPM — каждый HIT всё равно проходит через приложение. На заметном трафике разница с Varnish, который отдаёт HIT вообще без PHP, становится ощутимой.

Обязательно ли переключать индексацию в Update by Schedule?

Для прода — практически да: Update on Save не масштабируется на каталог из тысяч товаров с частыми правками цен. Но Update by Schedule требует рабочего и мониторимого cron — без присмотра сама эта настройка становится источником рассинхронизации данных.

Elasticsearch или OpenSearch — что выбрать для новой установки?

Обе линии совместимы с современными релизами Magento Open Source в рамках официально заявленной поддержки конкретной версии — уточняйте требования вашей ветки перед установкой. OpenSearch как форк с более открытой лицензией — частый выбор для новых self-hosted проектов.

Как понять, что кэш настроен неправильно, если сайт вроде бы работает?

Косвенный признак — расхождение цен или остатков на витрине с админкой, исчезающее после ручного cache:flush. Если это происходит регулярно, а не разово, проблема в инвалидации по тегам, а не в том, что кэш «просто устарел».

Сколько стоит содержать такой стек по сравнению с SaaS-решением?

Self-hosted Magento дороже по операционному вниманию (администрирование, обновления, мониторинг), но не привязывает к комиссии с оборота и даёт полный контроль над данными — компромисс, типичный для self-hosted вообще, не специфичный для e-commerce.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →