Предположим есть некоторый блок, который обновляется тяжелым запросом. Предположим этот запрос выполняется 5 секунд.
Есть посещаемый сайт, на котором этот блок показывается например 10 пользователям в секунду.
Допустим мы кешируем этот блок на некоторое время. Пусть это будет 10 минут.
Итак что будет когда эти 10 минут заканчиваются. Блок запрашивает пользователь №1. В кеше его нету - система пытается обновить кеш путем выполнения "тяжелого запроса". Запрос как выше упоминалось выполняется 5 секунд. За это время блок необходимо будет показать еще 49 пользователям и для этого снова будет запущено выполнение "тяжелого запроса"… Системе от этого станет плохо… и тяжелый запрос будет выполнятся еще медленее.
Все цифры из головы, просто для объяснения проблемы.
кэшировать не блок, а результат запроса, без экспирации, записывать в тотже мемкеш дату обновления определеного блока, обновлять через хх минут кеш результата запроса.
Если это обновление делать общим кодом - то возникнет аналогичная проблема. При выдаче данных всем пользователям во время обновления - каждый будет пытаться обновить кеш данных.
Если подумать дальше, то ваша подсказка позволяет придумать вот такой ход.
Первый процесс, который посчитает, что "пора обновить кеш" в самом начале обновляет дату обновления блока. Это позволит другим процессам использовать старые данные, а у первого будет время неспеша получить данные и обновить кеш блока.
TrojaNFlash, спасибо за подсказку. Может еще у кого-то идеи будут?
В свете вышеизложенных предложений, родилось более-менее красивое решение. Может кому-то пригодится.
Буду благодарен за критику и советы.
class MyCache extends CFileCache
{
public $expire_delta = 30; // Запас времени на обновление кеша
public $expire_suffix = '_expire';
protected function getValue($key)
{
$value = parent::getValue($key);
if ($value) { // Если значение есть в кеше, проверяю не пора ли его обновить
if (time() > parent::getValue($key . $this->expire_suffix)) { // Пора обновлять кеш
parent::setValue($key . $this->expire_suffix,time()+$this->expire_delta,$this->expire_delta);
return null; // Делаю вид что кеш истек и его нужно обновить, но для следующих запросов в течении expire_delta секунд будет выдаваться старый кеш.
};
};
return $value;
}
protected function setValue($key,$value,$expire)
{
return (parent::setValue($key,$value,$expire + $this->expire_delta) && parent::setValue($key . $this->expire_suffix,time() + $expire, $expire + $this->expire_delta));
}
}