Статьи  : 

Оптимизация загрузки прайсов

14 ноября 2016, 08:05

Постановка задачи



Имеется интернет-магазин, который загружает в свою базу прайсы от разных поставщиков (файлы xls, xlsx, csv). Файлы достаточно объемные, и их обработка создает значительную пиковую нагрузку на сервер. Требуется реализовать такую методику заливки данных, которая снизит эту нагрузку.


Общее описание



Проблема парсера, как мы уже отметили, заключается в том, что во время своей работы он потребляет значительное количество ресурсов сервера: занимает много оперативной памяти и создает нагрузку на процессор. Все это негативно влияет на работу других процессов, так что создается впечатление, будто сайт зависает/подтормаживает. В самых плохих случаях скрипт парсинга съедает всю доступную память и "умирает", не завершив обработку.

Чтобы уменьшить нагрузку, мы проведем два вида оптимизации: условно "внутреннюю" (настройки самого парсера) и "внешнюю" (когда и что парсить, в каком объеме и т.д.) Рассмотрим все эти моменты более подробно (описание дается безотносительно какой-либо CMS, так как это общие принципы оптимизации).


Оптимизации



Внутренние модификации:

Для парсинга прайсов используется библиотека phpExcel. Трюки по ее оптимизации достаточно широко описаны в интернете.

а) Необходимо включить сжатие данных в памяти:

$cacheMethod = PHPExcel_CachedObjectStorageFactory::cache_in_memory_gzip;
PHPExcel_Settings::setCacheStorageMethod($cacheMethod);


б) Режим "только чтение" тоже экономит ресурсы:

$objReader->setReadDataOnly(true);


в) Очень важно указывать только те столбцы, из которых реально читаются данные (столбцов может 10-15, а используются для парсинга только 3-4):

$filterSubset->set_range(array('A', 'B', 'D', 'E'));
$objReader->setReadFilter($filterSubset);


г) Также весьма полезно писать данные в базу "пачками" по 30-50 обработанных строк, а не после чтения каждой строки (сокращается время работы).


Теперь перейдем к методам внешней оптимизации:

д) Если есть возможность, то, разумеется, лучше выставить заливку данных на ночное время, когда посетителей на сайте мало.

е) Практика показывает, что обработка csv-файлов парсером идет заметно быстрее, чем xls и xlsx. Поэтому лучше сначала сконвертировать их в "легкий" формат:

cd /...upload_folder...; unoconv -f csv *.xls
cd /...upload_folder...; unoconv -f csv *.xlsx


ж) Наконец, разрежем подготовленные csv-шки на фрагменты по 10 тыс. строк, и будем заливать в базу не прайс целиком, а именно эти фрагменты.


Результаты измерений



Чтобы увидеть эффект от проделанной работы, мы используем скрипт, который каждую минуту измеряет нагрузку на сервер и записывает данные в лог-файл. Для сравнения были взяты два лога: один до оптимизации (первая строка), другой – после нее (вторая строка). Сравним значения по количеству вхождений:

всего (одна строка потерялась):

1439
1440


ежеминутная нагрузка > 0.1:

209
196


ежеминутная нагрузка > 0.3:

39
16


ежеминутная нагрузка > 0.5:

23
1


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


Недостатки



Разумеется, созданная нами система загрузки тоже не лишена недостатков. Мы уменьшили нагрузку на сервер, но вместо этого:

- стало труднее просматривать лог загрузки. Теперь вместо одной строки об успешной заливке данных получается 10-15 (в зависимости от размера файла)
- появились промежутки времени, когда старые данные прайса из базы очищены, а новые данные еще льются. Перезаливка одного прайса занимает примерно 15-20 минут (данные появляются постепенно – по мере обработки фрагментов прайса).

Насколько это критично (особенно второй пункт) – решается в каждом случае индвидуально, но в нашей ситуации это вполне терпимо.