Laravel · B2B-портал · поддержка

Портал на Laravelперестал справляться с нагрузкой

Оптовая компания принимала заказы через портал на Laravel: кабинеты клиентов, админка менеджеров, обмен с учётной системой. За несколько лет объём данных вырос — в рабочие часы список заказов открывался полторы–две минуты, а выгрузки обрывались по таймауту. Обратились к нам: нужно было найти проблемные места и ускорить портал, не останавливая его работу.

загрузка списка заказов на пике

1,5–2 мин5–10 сек

в 10–20 раз быстрее

запросов к базе на страницу

50+8–12

в 4–6 раз меньше

выгрузки Excel и PDF

таймаутв фоне

интерфейс не ждёт

остановок сервиса

0

за весь период работ

Личный кабинет оптового покупателя

Кабинет вырос в полноценную рабочую систему

Персональные цены, остатки по складам, заказ списком, аналитика закупок, документы и повтор типовых позиций — всё в одном кабинете. Именно эти экраны на пике нагрузки больше всего страдали от накопленного кода.

Рабочий стол: счёт, заказы, менеджер — типичный B2B-кабинет
Журнал заказов — экран, который чаще всего тормозил на пике нагрузки

Контекст

Сервис работал всё время — останавливать его нельзя было

Новую платформу заказчик не рассматривал: переписывание означало бы около полугода без развития продукта. Нужна была команда, которая снимет нагрузку в пиковые часы и оставит проект в поддерживаемом состоянии.

  1. 01

    Проект собирали годами

    B2B-портал для оптовых закупок: заказы, документы, отчёты для менеджеров. Первую версию делала другая команда, дальше ещё одна команда год за годом подключала модули и интеграции.

  2. 02

    Данных стало в разы больше

    Клиентов и заказов прибавилось. Решения, которые на старте работали нормально, к вечернему пику упирались в базу: экраны подвисали, выгрузки не доходили до конца, API отвечал с задержкой.

  3. 03

    Историю терять нельзя

    Бизнес завязан на текущую логику скидок, обмен с учётной системой и архив заказов. Переписывание означало около полугода без развития продукта.

  4. 04

    Подключились мы

    Задача была понятная: найти, что грузит базу и сервер, убрать это и навести порядок в коде. Замеры — на копии, правки — поэтапно, после проверки.

Диагностика

Проблема была в нескольких конкретных местах

На копии боевой базы замерили время ответа по сценариям менеджеров. Основная нагрузка шла от неоптимизированных запросов и их дублей в списках.

до 2 мин

Неоптимизированные выборки

Отчёты и фильтры по заказам собирались длинными JOIN, а полей, по которым менеджеры ищут и сортируют каждый день, в индексах не было. На выросших таблицах один такой запрос уходил в минуты.

50+

Дублирующиеся запросы в списках

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

каждый раз

Справочники пересобирались заново

Статусы, склады, типы цен и прочие редко меняющиеся данные брались из базы при каждом открытии страницы. Один и тот же набор строк пересобирался весь день.

синхронно

Выгрузки в момент клика

Excel и PDF собирались синхронно. Пользователь ждал у пустого экрана, а процесс PHP всё это время держал соединение и память.

Что сделали

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

Работали короткими итерациями: правка — проверка на копии — релиз. Время ответа сравнивали до и после каждого шага, поэтому месяц изменений не выкатывался одним куском.

01

Замерили

На копии боевой базы замерили, какие запросы тянутся дольше всего, и прошли частые сценарии: список заказов, карточка клиента, отчёт за период, выгрузка в Excel.

02

Переписали запросы, добавили индексы

Проблемные выборки собрали заново. Добавили индексы под те фильтры, с которыми менеджеры работают каждый день. Лишние поля из выборки убрали. Отчёты за период перевели на подсчёт порциями.

03

Убрали дублирующиеся обращения

В списках и карточках связи загружаются одним запросом на страницу. Для больших наборов добавили постраничную выдачу и ограничили глубину связей. Экспорт больших таблиц ушёл в фоновую очередь.

04

Закрыли справочники кэшем

Редко меняющиеся данные положили в Redis с понятным сроком жизни. Правка в админке сбрасывает только затронутый ключ.

05

Разобрали код по модулям

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

Вывод

Некоторые проблемы становятся заметными только на большом объёме данных

Проект на Laravel может работать годами, пока объём данных не дорастёт до точки, где старые запросы к базе, дублирующиеся обращения и синхронные выгрузки становятся проблемой на пике нагрузки. Переписывать всё с нуля имеет смысл, когда правки уже не окупаются. Сначала стоит оценить объём работ в текущей версии продукта и только потом принимать решение — часто это дешевле.

Оптимизируем ваш проект на Laravel

Изучим структуру проекта и базы, произведём замеры в проблемных местах сайта и предложим оптимальное решение.

Достаточно одного контакта.