Перейти к содержанию

Рекомендуемые сообщения

Была поставлена задача - переписать систему кэширования OpenCart без использования функции glob, т.к. при 15 тыс файлов в кэше она тормозит (даже при 20 вызовах $this->cache->get) .

post-27725-0-44457200-1430706630_thumb.png

Условия:

  • Кэширование на основе файлов:
  • Функционал не урезается, удаление файлов из кэша по маске файла так же остается доступным.
  • Все изменения в пределах одного файла.

Было принято решение спрятать expire вместе с сериализованными данными чтобы при получении файла можно было использовать любую функцию, а не только glob. И собственно, заменить glob в функции get т.к. она вызывается чаще всего. У оставшейся в классе функции glob добавлен флаг GLOB_NOSORT(хоть это и должно значить, что файлы не должны быть отсортированы, они все же сортируются функцией sort, с этим флагом они не будут сортированы функцией uasort, которая медленней).



 

<?php

class Cache {
	private $expire = 3600;
	public function get($key) {
		
		$file = DIR_CACHE . $key . '.cache';
		
		if (is_file($file)) {
			
			$data = unserialize(file_get_contents($file));

			if ($data['time'] < time()) {
				if (file_exists($file)) {
					@unlink($file);
				}
				return false;
			}
		
			return $data['data'];
		}
	}

	public function set($key, $value) {
		$this->delete($key);
		
		$data = array(
			'time' => time() + $this->expire,
			'data' => $value
		);
		
		$file = DIR_CACHE . $key . '.cache';

		$handle = fopen($file, 'w');

		fwrite($handle, serialize($data));

		fclose($handle);
	}

	public function delete($key) {
		$files = glob(DIR_CACHE . $key . '.cache', GLOB_NOSORT );

		if ($files) {
			foreach ($files as $file) {
				if (file_exists($file)) {
					@unlink($file);
				}
			}
		}
	}
	
	public function check(){
		$files = glob(DIR_CACHE . '*.cache', GLOB_NOSORT );

		if ($files) {
			foreach ($files as $file) {
				if (file_exists($file)) {
					$data = unserialize(file_get_contents($file)); 
					$time = $data['time'];
					if ($time < time()) {
						@unlink($file);
					}
				}
			}
		}
	}
	
	function __destruct() {
		if (mt_rand(0, 300) == 15) {
			$this->check();
		}
	}

}
?> 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В старых версиях опенкарта (до 1.5.3.1 или 1.5.4.1) в файле кеша был конструктор в котором удалялись все устаревшие файлы кеша. Потом его удалили, наверное потому что он вызывался при каждой загрузке и если файлов кеша много то он мог сильно тормозить весь магазин.  

Но удалив этот конструктор проблему то не решили. И теперь удалить файл из кеша можно только по ключу напрямую вызвав метод удаления или установки кеша по этому ключу. А что если пользователь установил например модуль фильтра, который создал тысяч десять файлов кеша, а потом этот модуль удалил? Или категорию, которая в кеше удалили и ее ключ уже никогда вызван не будет? И куча этих файлов будет лежать мертвым грузом в паке кеша вечно?
Или я не прав и где-то это все-таки удаляется?
Если нет, то контроллер можно было бы добавить, но вызывать функцию очистки всего кеша не постоянно при каждой загрузке, а например при каждой сотой или тысячной загрузке (например даже через rand) или как-то по другому вызывать периодически. 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Приветствую. Этот вариант я тоже рассматривал. Но, например, при обновлении цены у товара нужно удалить все файлы, к которых содержится старая цена, например в фильтре или других модулях. Проще сделать это по маске файла $this->cache->delete('filterpro*'), $this->cache->delete('latest*'). Нежели флушить весь memcached сервер. Механизма получения списка ключей в нем нет. Поэтому по маске удалить нельзя, да, и полного названия ключа в файлам кэша у нас тоже нет, поэтому вариант с memcached был отвергнут.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Еще столкнулся с проблемой, когда файл кэша удаляется в промежуток между проверкой и получением данных) Эта проблема так же наблюдается в коробочном классе кэширования.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Попробуйте этот класс http://code-igniter.ru/wiki/Cache.

В нем нет глупости по типу glob, есть тегированние. И он довольно быстрый - используется разделение кешей на подпапки, довольно быстрая инвалидация данных. Можно дописать массовое удаления всех данных по тегу.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

sv2109,
 
Я все еще думаю над правильной реализацией, на которую не будут ругаться другие программисты(решение в пределах класса). Еще пытаюсь решить проблему с не атомарными операциями, т.к. запрашиваемый файл может удалиться в промежуток между проверкой и удалением. 
 
Кстати, изменение класса очень сильно повлияло на скорость. 16 тыс файлов было из-за кэширования в ненужных местах, сейчас файлов в районе 2к.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

а как вы этот участок объясните? 

			if ($time < time()) {
				if (file_exists($file)) {
					@unlink($file);
				}
			}
		
			return $data['data'];

зачем отдавать данные из "протухшего" кеша?

 

и зачем это?

preg_replace('/[^A-Z0-9\._-]/i', '', $key . '.cache')

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Первое исправлю, не заметил :-) . Второе было в стандартном классе. Если Вы имеете ввиду расширение cache, то просто так, его убирать не буду, уберу cache в начале. preg_replace для того, чтобы оставить только буквы и цифры в ключе. Это есть в стандартном классе, в принципе - тоже можно убрать. Т.к. имена в основном (в модулях) генерятся из хешей, слов на латинице, точек и числовых значений.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

preg_replace оставьте.

как раз чтобы и дальше генерировались "только буквы и цифры в ключе".

иначе у кого-нибудь может начаться ахтунг.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

да, лучше оставить, я изначально не так прочитал регулярку, потому спросил

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Прошу поправить, если сделал что-то не так. Подсказать. Т.к. валидация кэша должна происходить в пределах класса было решено добавить ее в деструктор с условием mt_rand(0,600) == 15; (@sv2109).

Только не пойму куда воткнуть clearstatcache(), она здесь нужна т.к. используются кэшируемые функции filesize() и file_exists(), а функция unlink сама выполняет clearsatcache().

Вот этот участок:

'cache.' . preg_replace('/[^A-Z0-9\._-]/i', '', $key) . '.cache'

оставил для совместимости с модулями, которые работают с кэшем. Расширение - для удобства.

<?php

class Cache {
	private $expire = 3600;

	public function get($key) {
		
		$file = DIR_CACHE . 'cache.' . preg_replace('/[^A-Z0-9\._-]/i', '', $key) . '.cache';

		if (!$fp = @fopen($file, 'r')) return false;		
		flock($fp, LOCK_SH);
		$data = unserialize(fread($fp, filesize($file))); 
		flock($fp, LOCK_UN);
		fclose($fp);

		if ($data['time'] < time()) {
			if (file_exists($file)) {
				unlink($file);
			}
			return false;
		}
		
		return $data['data'];
		
	}

	public function set($key, $value) {
		$this->delete($key);
		
		$data = array(
			'time' => time() + $this->expire,
			'data' => $value
		);
		
		$file = DIR_CACHE . 'cache.' . preg_replace('/[^A-Z0-9\._-]/i', '', $key) . '.cache';
		
		if (!$fp = fopen($file, 'w')) return false;
		if (flock($fp, LOCK_EX)){  
			fwrite($fp, serialize($data));  
			flock($fp, LOCK_UN);
			fclose($fp);
		} else {
			return false;  
		}
	}

	public function delete($key) {
		$file = DIR_CACHE . 'cache.' . preg_replace('/[^A-Z0-9\._-]/i', '', $key) . '.cache';
		if (file_exists($file)) {
			@unlink($file);
		}
	}
	
	public function validate(){
		$files = glob(DIR_CACHE . 'cache.*.cache', GLOB_NOSORT );

		foreach ($files as $file) {
			if ($fp = @fopen($file, 'r')){

				flock($fp, LOCK_SH);
				$data = unserialize(fread($fp, filesize($file)));
				flock($fp, LOCK_UN);
				fclose($fp);
				
				if ($data['time'] < time()) {
					@unlink($file);
				}
			}
		}
	}
	
	function __destruct() {
		if (mt_rand(0, 600) == 15) {
			$this->validate();
		}
	}

}
?> 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Почти заключительная версия класса:

<?php

class Cache {
	private $expire = 3600;

	public function get($key) {
		
		$file = DIR_CACHE . 'cache.' . preg_replace('/[^A-Z0-9\._-]/i', '', $key) . '.cache';
		
		if (file_exists($file)) {
			$fp = fopen($file, 'r');
			flock($fp, LOCK_SH);
			$data = unserialize(fread($fp, filesize($file))); 
			flock($fp, LOCK_UN);
			fclose($fp);

			if ($data['time'] < time()) {
				if (file_exists($file)) {	
					unlink($file);
				}
				return false;
			}
			
			return $data['data'];
		}else{
			return false;
		}
		
	}

	public function set($key, $value) {
		$this->delete($key);

		$data = array(
			'time' => time() + $this->expire,
			'data' => $value
		);
		
		$file = DIR_CACHE . 'cache.' . preg_replace('/[^A-Z0-9\._-]/i', '', $key) . '.cache';
		
		if (!$fp = fopen($file, 'w')) return false;
		if (flock($fp, LOCK_EX)){  
			fwrite($fp, serialize($data));  
			flock($fp, LOCK_UN);
			fclose($fp);
			
			clearstatcache();
			
			return true;
		} else {

			return false;  
		}
	}

	public function delete($key) {
		$file = DIR_CACHE . 'cache.' . preg_replace('/[^A-Z0-9\._-]/i', '', $key) . '.cache';
		if (file_exists($file)) {
			unlink($file);
		}
	}
	
	public function validate(){
		$files = glob(DIR_CACHE . 'cache.*.cache', GLOB_NOSORT );
		
		error_reporting(0);

		foreach ($files as $file) {
			if ($fp = @fopen($file, 'r')){

				flock($fp, LOCK_SH);
				$data = unserialize(fread($fp, filesize($file)));
				flock($fp, LOCK_UN);
				fclose($fp);
				
				if ($data['time'] < time()) {
					if (file_exists($file)) {
						unlink($file);
					}
				}
			}
		}
	}
	
	function __destruct() {
		if (mt_rand(0, 600) == 15) {
			$this->validate();
		}
	}

}
?> 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

кто готов провести тесты ? )

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Зачем хранить дату в массиве, если правильнее проверять дату изменения файла?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

справедливо. можно кучу времени сэкономить 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

а разве filemtime() не дисковая операция?

Тем более, что данные все равно проходят чрез unserialize()

Другой вопрос, что данные можно сжимать, но этот вопрос требует исследования для разного хостинга, что быстрее чистая запись/чтение или zip-запись/чтение-unzip

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

а разве filemtime() не дисковая операция?

Тем более, что данные все равно проходят чрез unserialize()

Другой вопрос, что данные можно сжимать, но этот вопрос требует исследования для разного хостинга, что быстрее чистая запись/чтение или zip-запись/чтение-unzip

 

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

 

По поводу тестов. Использовался ApacheBenchmark, думаю, его будет достаточно.

Кол-во файлов в кэше на время начала тестирования каждого класса - 500, по окончании 600-800 (посетителей много).

 

Стандартный класс кэширования

post-27725-0-00180800-1431522533_thumb.png

Кэширование без использования функции glob (с использованием filemtime). 

post-27725-0-66952500-1431522552_thumb.png

 

Кэширование без использования функции glob (хранение даты в массиве с данными). 

post-27725-0-68954100-1431522569_thumb.png

Поделиться сообщением


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

 

Я это и написал...

 

на паре хостингов, я вообще не кеширую  data = array() ; Т.е. операции с базой быстрей, чем кеширование пустого результата

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

 

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

 

По поводу тестов. Использовался ApacheBenchmark, думаю, его будет достаточно.

Кол-во файлов в кэше на время начала тестирования каждого класса - 500, по окончании 600-800 (посетителей много).

 

Стандартный класс кэширования

Кэширование без использования функции glob (с использованием filemtime). 

 

Кэширование без использования функции glob (хранение даты в массиве с данными). 

 

Тут вся соль в инвалидации данных. С файлтайм. Если дата протухла - инвалид. С датой в файле. Получить десериализовать. Проверить время.

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Тут вся соль в инвалидации данных. С файлтайм. Если дата протухла - инвалид. С датой в файле. Получить десериализовать. Проверить время.

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

 

Никакой статистической ошибки тут нет. Все дело в самой статистике и частоте запросов (кол-ве посетителей), а в нашем случае с ApacheBenchmark. При низкой частоте запросов (реальный проект) хранение времени в файле - минус, т.к. если данные протухли, то зря тратится время на unserialize. При большой (в нашем случае, 500 запросов за 3 минуты) - плюс т.к. данные десериализуются не зря (кэш не протух) и меньше работы с диском. Отсюда и экономия 10 сек, т.е. filemtime (10 запросов на страницу) занимает ~0.002 сек, что недалеко от истины. 

 

Исходя из этого я думаю, что правильней будет использовать filemtime т.к. проектов на opencart с такой нагрузкой, чтобы хранение даты в файле выходило в плюс - просто нет.

 

Я сам немного не понял, что написал, но мозг думает, что все правильно. Так что готов расписать более подробно-непонятно для тех кто не понял.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Рекомендуемый вариант класса с filemtime:

<?php

class Cache {
	private $expire = 3600;

	public function get($key) {
		
		$file = DIR_CACHE . 'cache.' . preg_replace('/[^A-Z0-9\._-]/i', '', $key) . '.cache';
		
		if (file_exists($file)) {
			$fp = fopen($file, 'r');
			flock($fp, LOCK_SH);
			$data = unserialize(fread($fp, filesize($file))); 
			flock($fp, LOCK_UN);
			fclose($fp);

			if ((filemtime($file) + $this->expire) < time()) {
				if (file_exists($file)) {	
					unlink($file);
				}
				return false;
			}
			
			return $data;
		}else{
			return false;
		}
		
	}

	public function set($key, $value) {
		$this->delete($key);
		
		$file = DIR_CACHE . 'cache.' . preg_replace('/[^A-Z0-9\._-]/i', '', $key) . '.cache';
		
		if (!$fp = fopen($file, 'w')) return false;
		if (flock($fp, LOCK_EX)){  
			fwrite($fp, serialize($value));  
			flock($fp, LOCK_UN);
			fclose($fp);
			
			clearstatcache();
			
			return true;
		} else {

			return false;  
		}
	}

	public function delete($key) {
		$file = DIR_CACHE . 'cache.' . preg_replace('/[^A-Z0-9\._-]/i', '', $key) . '.cache';
		if (file_exists($file)) {
			unlink($file);
		}
	}
	
	public function validate(){
		$files = glob(DIR_CACHE . 'cache.*.cache', GLOB_NOSORT );
		
		error_reporting(0);

		foreach ($files as $file) {
			if (file_exists($file)) {
				if ((filemtime($file) + $this->expire) < time()) {
					unlink($file);
				}
			}
		}
	}
	
	function __destruct() {
		if (mt_rand(0, 600) == 15) {
			$this->validate();
		}
	}

}
?>

 

Для тех, кто у кого стоит модуль Блог | Новости | Галерея | Отзывы и решит заменит свой класс на этот, то в файле system/library/agoo/cache.php нужно заменить функции get, set, delete на те, что находятся в этом классе.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Пример - дочернии категории

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Пример - дочернии категории

 

Я не рассматривал такой вариант т.к. процент таких запросов очень мал. 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну... почему же...

 

Вы строите дерево категорий в верхнем меню

а затем дерево категорий в модуле категорий

 

getCategories()

 

Хотя сам метод и кешируем... но все же...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти

  • Похожий контент

    • От Boriskin
      300.00 руб
      Скачать/Купить дополнение


      Продвинутое кэширование - BrainCache
      ИНСТРУКЦИЯ ПО УСТАНОВКЕ
      Что такое кэш запросов?
      Кэш запросов можно представлять себе как хеш, ключами которого являются запросы, а значениями — результаты запросов.
      В OpenCart уже есть поддержка кэша! Зачем мне нужен BrainCache?
      Использование стандартного метода кэширивания предполагает под собой работу со всеми файлами, где нужно кэширивание со всеми вытекающими отсюда последствиями:
      децентрализованный доступ к параметрам кэшеривания
      наличие множественных вызовов методов работы с кэшом в рамках всего MVC
      отсутствие правил и исключений кэшеривания для каждого запроса
      отсутствие фильтрации запросов, т.е кэшиются запросы без анализа строк
      отсутствие фильтрации прав доступа вызовов кэшеривания по Имени файла, Классу и Методу

      Что умеет BrainCache?

      1.0 beta поддержка профилей настроек кэшеривания;
      централизованный контроль и обработка всех вызовов и обращений к БД MySQL;
      выводить часто изменяющиеся данные в отдельный массив и устанавливать для каждого элемента время кэша, где 0 — запрет кэшеривания. Для удобства добавлены константы с предопределенным значением времени: МИНУТА, ДЕНЬ, НЕДЕЛЯ, МЕСЯЦ, ГОД, ВИСОКОСНЫЙ ГОД;
      устанавливать стандартное значение времени кэша, при отсутвии удовлетворяющих правил кэшеривания (если правила для запроса отсутствуют или не подошли);
      установка ограничений доступа к таблицам БД не относящихся к магазину, но находящихся в рамках одной базы (Сценарий выдаст предупреждение и завершит работу);
      установка пути директории кэшеривания для текущего профиля;
      установка ограничения доступа к кэшу по времени для Классов, Методов классов, Метода Класса выполняющих запрос
      установка ограничения доступа к кэшу по времени для пути и имени выполняющих запросов скриптов;

      Фиксы:
      Исправлена ошибка доступа к админ-панели
      Оптимизирован цикл поиска по ассоционному массиву, разделена логика условий
      Добавлен редирект на страницу 404, в случае срабатывания блокирующего условия

      Совместимость:
      Проверялось на v1.5.4.1, но должен быть совместим со всеми версиями, потому, что для установки не нужно вносить множественные изменения.
      Добавил Boriskin Добавлено 13.03.2013 Категория Кэширование, сжатие, ускорение  
    • От le75
      Ребят, кто сталкивался или подскажет при включении кэшированя на стороне браузера в .htaccess, не корректо работает админ панель: менеджер изображений, товары, добавление товаров и т.д. Тоесть отображается всё закешированное ранее, и только после очистки кеша браузера видны изменения(но это до первых новых правок). На стороне пользователя работает корректно и без очистки кэша. Тема дефолтная и кэширование стандартное если что:
      <ifModule mod_deflate.c> AddOutputFilterByType DEFLATE text/html text/plain text/xml application/xml application/xhtml+xml text/css text/javascript application/javascript application/x-javascript </ifModule> <ifModule mod_expires.c> ExpiresActive On ExpiresDefault "access plus 1 days" ExpiresByType image/x-icon "access plus 1 month" ExpiresByType image/jpeg "access plus 4 weeks" ExpiresByType image/png "access plus 30 days" ExpiresByType image/gif "access plus 43829 minutes" ExpiresByType application/x-shockwave-flash "access plus 2592000 seconds" ExpiresByType text/css "access plus 604800 seconds" ExpiresByType text/javascript "access plus 604800 seconds" ExpiresByType application/javascript "access plus 604800 seconds" ExpiresByType application/x-javascript "access plus 604800 seconds" ExpiresByType text/html "access plus 43200 seconds" ExpiresByType application/xhtml+xml "access plus 600 seconds" ExpiresByType application/x-font-ttf "access plus 1 month" ExpiresByType font/opentype "access plus 1 month" ExpiresByType application/x-font-woff "access plus 1 month" ExpiresByType image/svg+xml "access plus 1 month" ExpiresByType application/vnd.ms-fontobject "access plus 1 month" </ifModule>
    • От supmener
      Нашёл несколько ссылок. Прошу поделиться опытом, кто уже тестировал, чтобы облегчить ознакомление с этими решениями. На что ещё можно обратить внимание?
       
      Сборник советов
      http://fedorenko.pp.ua/kak-uskorit-vash-magazin-na-opencart/
       
      Speed Thrust
      http://www.opencart.com/index.php?route=extension/extension/info&extension_id=26417&filter_search=cache&filter_download_id=43&page=2
       
      Free Page Cache for OC 2.X (V2pagecache)
      http://www.opencart.com/index.php?route=extension/extension/info&extension_id=19079&filter_search=cache&filter_download_id=44
      http://forum.opencart-russia.ru/threads/v2pagecache-kehshirovanie-uskorenie-opencart-2-0-russkaja-versija.1490/
       
      Лог медленных запросов
      https://opencartforum.com/files/file/2764-%D0%BB%D0%BE%D0%B3-%D0%BC%D0%B5%D0%B4%D0%BB%D0%B5%D0%BD%D0%BD%D1%8B%D1%85-%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D0%BE%D0%B2-%D0%B4%D0%BB%D1%8F-opencart-2x-ocmod/
       
      BOOST - ускоритель OpenCart + AJAX загрузка модулей 2.0
      https://opencartforum.com/files/file/2612-boost-%D1%83%D1%81%D0%BA%D0%BE%D1%80%D0%B8%D1%82%D0%B5%D0%BB%D1%8C-opencart-ajax-%D0%B7%D0%B0%D0%B3%D1%80%D1%83%D0%B7%D0%BA%D0%B0-%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D0%B5%D0%B9/
       
    • От supmener
      После установки товаров нужно создать автоматически обращение к каждой странице с заданной периодичностью, чтобы картинки закэшировались и сайт не нагружался частыми обращениями. Как это лучше сделать? Или может настройками или модулем каким - то это можно реализовать? Хочу заранее, так как самый первых посетителей не хочется ставить в неуютное положение при посещении сайта.
    • От supmener
      Как очистить кэш в Opencart 2?
       

  • Последние посетители   0 пользователей онлайн

    Ни одного зарегистрированного пользователя не просматривает данную страницу

×

Важная информация

На нашем сайте используются файлы cookie и происходит обработка некоторых персональных данных пользователей, чтобы улучшить пользовательский интерфейс. Чтобы узнать для чего и какие персональные данные мы обрабатываем перейдите по ссылке. Если Вы нажмете «Я даю согласие», это означает, что Вы понимаете и принимаете все условия, указанные в этом Уведомлении о Конфиденциальности.