OpenCart под нагрузкой: что ломается первым в каталоге
Каталог OpenCart редко тормозит из-за одной причины. На практике первыми заканчиваются PHP-FPM-воркеры, упирается база данных или замедляются модификаторы и фильтры. Разбираем, как найти узкое место без гадания.

Каталог OpenCart может начать отдавать страницы по несколько секунд задолго до падения сервера. Обычно первыми заканчиваются PHP-FPM-воркеры, затем растёт очередь запросов к MySQL или MariaDB, а подключённые фильтры и модификаторы усиливают нагрузку на каждый просмотр категории. Ниже — разбор для OpenCart 3.0.x: где искать задержку, какие измерения снять и почему увеличение числа ядер не всегда помогает.
Сначала зафиксируйте, что именно считается нагрузкой
Фраза «сайт тормозит» слишком неточна для диагностики. Отдельно измеряйте страницу категории, карточку товара, поиск и фильтр. У них разные контроллеры, запросы и наборы расширений.
- Запишите версию OpenCart 3.0.x, PHP, веб-сервера и MySQL или MariaDB.
- Отделите время ответа приложения от времени ожидания соединения и загрузки изображений.
- Снимите p50, p95 и p99 времени ответа, количество запросов в секунду и долю ответов 5xx.
- Проверьте, меняется ли результат для гостя и авторизованного покупателя.
- Повторите замер без CDN и с ним, если CDN используется: кеш на границе может скрыть проблему приложения.
Нужен один и тот же сценарий: например, открыть категорию с несколькими десятками товаров, применить фильтр, перейти на следующую страницу и открыть карточку. Иначе сравнение «до и после» будет ненадёжным.
Под нагрузкой ломается не самый медленный запрос, а тот слой, который первым исчерпывает конечный ресурс: воркеры, соединения с базой, CPU, память или дисковый ввод-вывод.
Что обычно заканчивается первым
| Симптом | Вероятный слой | Что измерить | Риск ошибочного вывода |
|---|---|---|---|
| Запросы стоят в очереди, CPU PHP высокий | PHP-FPM или код расширений | Активные и занятые воркеры, время выполнения, slow log | Увеличение числа воркеров может перегрузить базу |
| PHP ждёт базу, растёт число медленных запросов | MySQL или MariaDB | Slow query log, планы EXPLAIN, блокировки | Индекс ускоряет чтение, но увеличивает цену записи |
| Категория медленнее карточки | Связи товаров, сортировка, фильтр | SQL категории, количество строк, сортировка | Виноват может быть не каталог, а расширение фильтра |
| После очистки кеша сайт резко замедляется | Кеш приложения или файловая система | Попадания и промахи кеша, I/O, время прогрева | Большой кеш не заменяет корректную инвалидацию |
| Страница HTML быстрая, изображения медленные | Ресайз изображений, storage или CDN | Время генерации миниатюр, размер файлов, cache hit | Оптимизация SQL не изменит загрузку картинок |
Медленный запрос — запрос, который попадает в журнал медленных запросов из-за настроенного порога времени. Порог задаётся в конфигурации сервера базы и не означает, что любой запрос из журнала одинаково вреден.
PHP-FPM: очередь появляется раньше падения
Каждый запрос к каталогу занимает PHP-FPM-воркер, пока OpenCart выполняет PHP-код, обращается к базе, читает файлы и собирает HTML. Если все воркеры заняты, новые запросы ждут свободный процесс. Пользователь видит медленный ответ, хотя сервер ещё может показывать умеренную загрузку CPU.
Смотрите на число активных и простаивающих процессов PHP-FPM, очередь, перезапуски из-за лимита памяти и максимальное число дочерних процессов. Названия метрик зависят от конфигурации и способа мониторинга. Важны не сами значения, а совпадение пиков задержки с исчерпанием воркеров.
Почему расширения меняют картину
В OpenCart модификаторы OCMOD, события и сторонние расширения могут добавлять обработчики к стандартному пути запроса. Фильтр, SEO-модуль, интеграция с поиском или персонализация способны выполнять дополнительную работу на каждой странице категории. После установки расширения сравнивайте трассировку и время ответа с контрольным стендом, а не только с главной страницей.
Признак этого класса проблем — база и CPU не выглядят перегруженными, но один сценарий каталога стабильно медленнее остальных. Временно отключать расширение на рабочем магазине опасно: сначала сделайте копию и повторите тест на staging.
База данных: каталог платит за фильтры и сортировку
Страница категории обычно должна связать товары с категорией, проверить доступность и статус, применить сортировку и ограничение по странице. Фильтры добавляют условия, соединения и иногда отдельные подзапросы. Чем больше товаров и вариантов фильтра, тем выше цена запроса.
Сначала включите журнал медленных запросов на тестовом окружении или в согласованный период. Затем найдите запросы, которые совпадают по времени с обращениями к каталогу. Для каждого проверьте план выполнения через EXPLAIN в поддерживаемой вашей версией MySQL или MariaDB форме. Смотрите, использует ли запрос ожидаемый индекс, сколько строк он проверяет и выполняется ли сортировка через временную структуру.
Почему один индекс не лечит весь каталог
Индекс, полезный для связи товара с категорией, не обязательно ускорит сортировку по цене или фильтрацию по атрибуту. Составной индекс должен соответствовать конкретному условию и порядку операций, а не просто содержать «все популярные поля».
Не добавляйте индексы по совету из форума без замера. Они занимают место, увеличивают стоимость INSERT и UPDATE и могут не использоваться оптимизатором. Перед изменением сохраните схему и проверьте план на копии базы с объёмом данных, близким к боевому.
Изображения и файловый кеш: тихий источник задержек
Каталог может выглядеть проблемным из-за картинок. При первом обращении к новому размеру изображения OpenCart или расширение может проверить наличие миниатюры, создать её и записать в storage. На медленном диске или сетевом хранилище это добавляет задержку, особенно когда одна страница содержит много новых изображений.
Проверьте, различаются ли первый и повторный запросы к одной категории, где хранятся миниатюры, сколько места осталось и не меняются ли права доступа к каталогу storage. Если повторный запрос заметно быстрее, проблема может быть в прогреве, а не в SQL.
Кеширование здесь не универсальное лекарство. После изменения цены, наличия или изображения устаревшая страница должна перестать использовать старые данные. Инвалидация кеша — отдельная тема; здесь важен только её эффект на диагностику: сравнивайте холодный и тёплый запросы отдельно.
Как провести разбор под нагрузкой
- Опишите сценарий. Выберите URL категории, размер страницы, фильтр и тип пользователя. Зафиксируйте набор товаров и параметры сортировки.
- Снимите базовую линию. Запишите p50, p95, p99, долю ошибок, RPS, CPU, память, дисковый ввод-вывод, активные PHP-FPM-процессы и подключения к базе.
- Разделите ожидание. Сопоставьте время ответа прокси, PHP-FPM и базы. Если инструменты не показывают разбиение, добавьте наблюдаемость на уровне сервера, а не делайте вывод по общему времени.
- Найдите повторяющийся SQL. Свяжите медленный запрос с конкретным URL и проверьте его план. Один редкий запрос не объясняет систематическую задержку без подтверждения по журналу.
- Сравните расширения. На копии проекта отключайте группы модификаторов по одной и очищайте кеш модификаций. Если задержка исчезла, возвращайте компоненты по одному и фиксируйте виновника.
- Повторите тест. Используйте тот же сценарий и сопоставимую параллельность. Только после этого сравнивайте результат с базовой линией.
Нагрузочный тест запускайте не по боевому магазину без согласования. Особенно опасны сценарии, которые создают заказы, меняют корзину или вызывают внешние интеграции.
Где подход ломается
Высокий RPS не всегда означает проблему кода
Если CDN отдаёт HTML или статические изображения из кеша, приложение видит только промахи. Если кеш отключён, один и тот же RPS может создать совершенно другую нагрузку. В отчёте указывайте долю попаданий в кеш и условия прогрева.
Добавление PHP-FPM-воркеров может ухудшить ситуацию
Больше воркеров полезно только при наличии свободных CPU, памяти и мощности базы. Иначе процессы начинают конкурировать за соединения и CPU, а p95 растёт. Настройку выбирайте по наблюдаемому пределу, а не по числу ядер «на глаз».
Фильтр может быть отдельным продуктом
Если расширение строит собственный индекс или обращается к внешнему поиску, оптимизация стандартного запроса OpenCart не устранит его задержку. Сначала определите владельца SQL и источник данных, затем выбирайте исправление.
Что делать после диагностики
Сначала поставьте мониторинг p95 и p99 для отдельных маршрутов каталога, количества медленных SQL-запросов, занятых PHP-FPM-воркеров, ошибок 5xx и доли попаданий в кеш. Затем заведите регрессионный сценарий для главной категории, фильтра и карточки товара.
Изменения в индексах, PHP-FPM, OCMOD и кешировании внедряйте по одному. Для каждого сохраняйте план запроса, параметры нагрузки и результат до и после. Если магазин работает на OpenCart 4.x или сильно изменённой сборке OpenCart 3, повторите проверку по исходному коду и документации именно этой версии: внутренний путь запроса и совместимость расширений могут отличаться.
Контент-конвейер: Из одной идеи — текст, изображение, озвучка и ролик. Один заказ вместо четырёх.
Спросить за 60 ₽Источники: OpenCart 3.0.x — исходный код, OpenCart Documentation
Частые вопросы
Что ломается в OpenCart первым при росте нагрузки?
Почему главная страница быстрая, а категория тормозит?
Стоит ли просто увеличить число PHP-FPM-воркеров?
Как понять, что виновата база данных?
Что делать, если у меня OpenCart 4.x?
Что проверить, если после оптимизации стало только хуже?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.