Статьи  : 

Производительность кеша в Opencart 1.5

6 декабря 2016, 08:00

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



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


Решение проблемы



Больное место опенкарта версии 1.5 – то, как в нем реализовано "родное" кеширование данных. Посмотрим файл system/library/cache.php:

public function __construct()
{
	$files = glob(DIR_CACHE . 'cache.*');
	
	if ($files)
	{
		foreach ($files as $file)
		{
			$time = substr(strrchr($file, '.'), 1);

			if ($time < time())
			{
				if (file_exists($file))
				{
					unlink($file);
					clearstatcache();
				}
			}
		}
	}
}


Как видно, при любых операциях с кешем (чтение, запись) происходит сканирование папки system/cache на наличие устаревших файлов (функция glob). При интенсивной работе сайта и большом количестве файлов кеша это станет серьезным тормозом в его работе. Поэтому первым делом была проверена папка кеша, где обнаружилось – ни много, ни мало – 120 тысяч файлов (!!) [причем многие не могли удалиться очень давно]. Разумеется, все они были почищены, а работа с кешем была исправлена так, чтобы:
а) данные группировались по папкам
б) очистка происходила независимо от работы сайта (через планировщик, раз в 10 минут)

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

Снижение нагрузки на хостинг
Снижение нагрузки на хостинг



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


Дополнительный анализ



Задача, хоть и была решена, но оставила после себя легкую неудовлетворенность. Что же именно вызывало проблемы? Как видно, тут есть два фактора:

а) время сканирования папки кеша функцией glob (задержка)
б) обработка полученного списка файлов (задержка + нагрузка)

Попробуем смоделировать ситуацию. Для тестов использован обычный компьютер (AMD Athlon(tm) II X2 245 Processor, 4 Гб оперативной памяти, стандартный HDD).


1. Смоделируем папки разной степени заполненности (1, 5, 10, 20, 50 и 100 тысяч файлов).

Заполним их тестовыми файлами:

$range = 1000;

for ($j = 100000; $j <= 100000 + $range; $j++)
{
	file_put_contents('scan/'.$range.'/'.$j.'.txt', $j);
}


Теперь выполним сканирование (100-кратный проход) каждой папки:

$mtime = explode(" ", microtime());
$start_time = $mtime[1] + $mtime[0];

$range = 1000;

for ($j = 0; $j < 100; $j++)
{
	$files = glob('scan/'.$range.'/1*');
	
	if ($files)
	{
		foreach ($files as $file)
		{
			$time = substr(strrchr($file, '.'), 1);

		}
	}
}

$mtime = explode(" ", microtime());

printf ("%f", $mtime[1] + $mtime[0] - $start_time);


На выходе мы имеем следующие результаты (пары "количество файлов в папке : время обработки в секундах"):

1000 : 0,149251
5000 : 0,883930
10000 : 1,853359
20000 : 3,931520
50000 : 10,774565
100000 : 23,346909


Как видно, затраченное время растет линейно, соответственно, чем больше файлов – тем больше задержка:

Производительность glob
Производительность glob



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


2. Более интересной представляется ситуация с нагрузкой.

Выполним многократный проход по кешу, попутно измеряя нагрузку командой top в консоли (мы использовали самую объемную папку):

$range = 100000;

for ($j = 0; $j < 200; $j++)
{
	$files = glob('scan/'.$range.'/1*');
	
	if ($files)
	{
		foreach ($files as $file)
		{
			$time = substr(strrchr($file, '.'), 1);

		}
	}
	sleep(1);
}


Данный код дает нагрузку 15-20% CPU и 1.5% Memory, что весьма много с учетом параметров компьютера (для сравнения, проход по папке с 10 тыс. файлов дает 3% CPU и 0.6% Memory). Для слабого хостинга, соответственно, проблема будет намного серьезнее.

Таким образом, в ситуации с сайтом это и было проблемным местом.


Читайте также: профайлер для отладки OpenCart 1.5