Начинать Одна система учета и отчетности, поддерживаемая нашей компанией, начала очень быстро расти по объему хранимых данных.
Система написана на PHP с использованием фреймворка Yii2. Первоначально отчеты строились с помощью библиотеки PhpSpreadsheet, которая заменила давно устаревший PhpExcel. Среди разных видов отчетности был один очень большой — по сути, полный набор всех данных, хранящихся в базе данных, должен быть выгружен в одну таблицу Excel. На начальном этапе проблем не было, но когда объём стал превышать многие сотни тысяч записей, скрипт генерации закачки начал отваливаться по таймауту.
Для начала мы подняли этот самый лимит и начали искать пути решения проблемы.
Но временное решение просуществовало недолго — проблема с лимитом времени превратилась в проблему с лимитом памяти.
Они добавили на сервер «ОЗУ» и вообще убрали Memory_limit для этой конкретной операции.
Очень скоро пользователи снова начали жаловаться на ошибки во время выполнения.
Нам также пришлось снять ограничение по времени для полного отчета.
Но сидеть и смотреть десять минут в экран с индикатором загрузки – не очень весело.
К тому же иногда отчет был нужен «здесь и сейчас», и каждая минута, потраченная на его формирование, оказывалась решающей.
Мы перестали экспериментировать с настройками окружения, почесали затылки и занялись оптимизацией кода.
Поиск решения
Первое, что было сделано, — это перевели скрипт отчетности в фоновый процесс, и пользователь следит за прогрессом через «прогресс-бар».Фоновое выполнение заданий было реализовано через механизм организации очередей с использованием Redis для хранения.
Работа в системе не прекращается, вы можете заниматься другими задачами и периодически возвращаться на страницу отчета, чтобы проверить, готов ли файл.
Как только файл будет создан, пользователю будет предложена ссылка для скачивания.
Но, как уже говорилось выше, иногда файл был нужен «сразу», и улучшение юзабилити не решало этой проблемы.
Тем временем объем данных продолжал расти, а время создания файла достигло 79 минут! Это совершенно неприемлемо, особенно если учесть, что отчетность — одна из основ функциональности этой системы.
Нет, все остальные детали работали как часы, но эта ложка дегтя испортила общее впечатление.
Первые результаты
Мы сели еще раз анализировать код. Первое, что было протестировано — это процесс выбора данных из базы данных.Но запросы уже оптимизированы в лучшем виде.
Хотя самый длинный запрос был ужасной выборки с пятью-шестью обращениями в чудовищную ФИАС, он был обработан за 2-5 секунд. Слабым местом было не оно, а формирование файла Excel. Начались попытки оптимизировать этот процесс.
Начиная от кеширования в redis, заканчивая извращениями типа формирования отдельных небольших файлов Excel в параллельных потоках и последующей склейки в один файл.
Но результат всегда был один и тот же: со временем проблема переросла в проблему с памятью и наоборот. Не было золотой середины, только перетекание из одной крайности в другую.
После определенного объема данных потребление ресурсов библиотеки начало расти в геометрической прогрессии и побороть это не удалось.
PhpSpreadsheet — не подходит для больших файлов.
В результате было принято решение сменить библиотеку.
Как вариант, напишите свой аналог для генерации файлов Excel.
Анализ и выбор инструмента
Мы не торопились писать велосипеды, а сначала провели анализ существующих решений.Из возможных вариантов меня интересовал только короб/излив.
Мы быстро переписали модуль, используя эту библиотеку.
В результате полный отчет был выполнен за 145 секунд. Напомню, последние тесты от PhpSpreadsheet — 79 минут, а здесь — 2,5 минуты! Проведено тестирование: увеличен объем данных в 2 раза.
Отчет был сформирован за 172 секунды.
Разница потрясающая.
Конечно, библиотека не имеет всех тех же функций, что и PhpSpreadsheet, но в данном случае достаточно минимального набора инструментов, поскольку скорость работы имеет решающее значение.
Расширение для Yii2
Окончательное решение было разработано как расширение для Yii2. Возможно, это будет кому-то полезно.Расширение позволяет загружать любой набор данных из GridView в Excel, сохраняя при этом фильтрацию и сортировку.
Использует yii/queue и box/spout в качестве зависимостей.
Имеет смысл использовать расширение для создания действительно больших файлов, ну хотя бы 50 000 строк =) На данный момент модуль, ставший основой расширения, лихо справляется с нагрузкой почти в 600 000 строк.
Ссылка на гитхаб: Расширение Yii2 ExcelReport Спасибо за внимание! Теги: #php #yii2 #Excel #генерация больших файлов #box spout #phpspreadsheet #php #Yii
-
Рамблер Взял На Себя Кубок России По Футболу
19 Oct, 24 -
5 Стадий Некомпетентности Программиста
19 Oct, 24 -
Подожди, Локомотив...
19 Oct, 24 -
Уверенность. Опять О Том, Как Там Круто
19 Oct, 24 -
Коды Грея И Проблемы Поиска
19 Oct, 24