Мои мысли и проекты
Создаем сайт на Lumen (Laravel) - Кеширование

Создаем сайт на Lumen (Laravel) - Кеширование

Работа с КЕШ-ем при мультисайтинге

Для корректной работы мультасайтинга необходимо доработать ещё один компонент - КЕШ. В Lumen есть кеширование, но оно одно на все сайты. Мне же нужно сделать свой КЕШ, который будет работать в пределах текущего SID. Для этого создам модуль Cache с singleton-ом с именем SCache. Реализация весьма простая, просто буду перенаправлять все вызовы на обычный Cache, но перед этим добавлять к ключу текущий SID.

<?php
namespace App\Modules\Cache;
use Cache;
use App\SID;

class Singleton implements \App\ISingleton
{
	// Получить имя псевдонима 
	static public function getAlias() { return 'SCache'; }
	// Используемое хранилище
	protected $store=null;
	function __construct($name=null) {
		// Используемое хранилище. По умолчанию текущее
		$this->store = Cache::store($name);
	}
	// Преобразовать ключ
	protected function _key($key) {
		// Добавить к ключу текущий SID
		return SID::get().'://'.$key;
	}
	// Вернуть объект для работы с другим типом КЕШ-а
	public function store($name) {
		return new Singleton($name);
		
	}
	// Перегзуить методы
	public function __call( string $name, array $arguments) {
		// Первый параметр - это ключ. Преобразовать его
		$arguments[0] = $this->_key($arguments[0]);
		// Вызвать метод
		return  call_user_func_array([$this->store,$name],$arguments);
	}
}

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

	// Получить значение и расчитать его с помощью функции обратного вызова если такого значения нет или это режим отладки
	public function rememberGet($key,$callback,$isTransform=true) {
		if($isTransform) {
			$key = $this->_key($key);
		}
		$isDebug = config('app.debug');
		if( $isDebug || !$this->store->has($key) ) {
			$ret = $callback();
			if(!$isDebug) {
				$this->store->forever($key,self::toSerialize($ret));
			}
		} else {
			$ret = unserialize($this->store->get($key));
		}
		return $ret;
	}

Cохранение данных в КЕШ до события

Создам метод для сохранения данных в КЕШ до наступления события. Т.е. данные будут удалены из КЕШ-а при наступлении определенного события. Этим методом можно пользоваться при кешировании запросов в БД. К примеру запрос из БД статьи можно закешировать до события изменения этой статьи. В этом случае будет минимизировано количество запросов в БД. Прототип метода:

rememberEvent($arg1,$arg2,...,$argN,$callback)

Из аргументов $arg1...$argN буду генерировать ключ для кеширования. А метод $callback будет вызываться для генерации данных если их нет в КЕШ-е. Схема работы функции

На схеме видно что сначала данные проверяются в КЕШ-е (2), а затем и в таблице БД (3). Связано это с тем, что некоторые виды КЕШ-а при переполнении могут обнуляться и в этом случае данные будут присутствовать в таблице БД, но отсутствовать в КЕШ-е. В этом случае нужно будет возвращать их из БД без вызова функции генерации данных и сохранять в КЕШ-е.

Также нужно предусмотреть возможность дочерних вызовов. Т.е. внутри функции генерации могут быть вызовы функции rememberEvent. Такой вызов будем называть дочерним. В случае разрушения(очистки) дочернего КЕШа родительский тоже должен быть разрушен(очищен). Поэтому при сохранении нужно учитывать иерархию вида "родительский-дочерние элемент".

Для сохранения данных в таблицу БД будем использовать три таблицы.

  • shasoft_cache_entrys - элементы КЕШ-а
  • shasoft_cache_events - события, привязанные к каждому элементу КЕШ-а
  • shasoft_cache_hiers - иерархия элементов КЕШ-а

Функция генерации данных имеет следующий вид

/**
  $controlEntry - объект контроля элемента КЕШ-а
  $arg1,...,$argN -аргументы функции rememberEvent($arg1,...,$argN,$callback) 
*/
function callback($controlEntry,$arg1,...,$argN) {
...
}

Объект контроля элемента КЕШ-а содержит метод который нужно использовать в функции генерации данных для привязки событий

/**
  Привязать событие к элементу КЕШ-а. При наступлении этого события данный элемент КЕШ-а (и все его родители) будет удален
  $arg1,...,$argN -аргументы события
*/
public function event($arg1,...,$argN)

Также есть метод в котором можно привязать функции для событий set(установка данных) и remove(удаление данных)

/**
  Привязать своих действий к элементу КЕШ-а. При наступлении этого события данный элемент КЕШ-а (и все его родители) будет удален
  $arg1,...,$argN -аргументы события
*/
public function on($name/* set или remove */,$fn)

В SCache добавим метод event

/**
  Указать что произошло событие
  $arg1,...,$argN -аргументы события
*/
public function event($arg1,...,$argN);

Данный метод будет возвращать объект с двумя доступными методами: event (аналог тому методу что описан выше) и send. Метод send будет служить для информирования системы о произошедших событиях которые перед этим были указаны методами event.

Типичный пример кеширования до наступления события (как раз из этого метода сделана картинка лога):

	$data = SCache::rememberEvent(123,function($controlApi,$id){
		$controlApi->event('test');
		$data = SCache::rememberEvent(123,345,function($controlApi,$id){		
			$controlApi->event('test2');
			return "Валера";
		});
		//
		return 'Диана & '.$data;
	});

И код для информирования системы о произошедшем событии. При его вызове будет сброшен КЕШ, который генерируется кодом выше.

	// Сообщить системе что произошли события
	SCache::event('test2')->send();

Так как вызывается событие test2 дочернего элемента КЕШ-а, то будет удален и он и родительский элемент.

0

Комментарии

Чтобы оставлять комментарии войдите на сайт. Вы можете сделать это через социальную сеть