Pull to refresh

Comments 23

у себя использую следующую схему:
1. на каждую модель propel навешивается таг с условным именем равным имени таблицы, при операциях с моделью (save, delete) в код внедряется очистка соответствующих тегов (билдеры пропела расточены).
2. На вью участки помечаются от каких тегов они зависят a, b, c
3. Дело техники дописать обработчик и механизм тегов кеширования
Тегирование — отличный вариант, достойный реализации в виде плагина; )
у меня не симфони а свой фв, поэтому увы :)
Реализация как реализация. А если классов сто тыщ?

Плагин оно както красивше.

Автор сверху кстати про html-кеширование. А вы про кеширование объектов.
кстати, еще одну штуку опишу — в тему, отложенные lazy запросы.
Идея в том, что в Propel дописывается билдер кторые генерит Lazy мапперы модели — образно это объект (м моей реализации), содержащий Criteria объект и Peer class, реализует итератор и getObject() ($peer::doSelectOne) и магию — и получается черным ящиком который снаружи выглядит как список обычных Propel инстансов.

В итоге, фактически запрос будет выполнен не в контроллере а переносится во вью «по требованию» — полный аналог Django.

Так вот, используя такой подход и теги кеша на вью вам не нужны партиалсы и вообще не нужно парить моск на этапе разработки — все делаете как обычно, а вот теги проставляете во вью уже на этапе оптимизации с профайлером и т.п.
При определенных условиях, с достаточно большим количеством компонентов на странице и простых запросах, я столкнулся с тем что кеш работает медленнее чем выборка из базы, правда это был обычный файловый кеш.
Я специально не стал затрагивать тему временных затрат, покольку все очень сильно завязано на конфигурацию сервера. Разумеется операция чтения данных из ФС значительно дороже по времени чем операция тения данных из оперативной памяти. Мы используем файловый кеш для dev-окружения, таким образом можно физически проверять работу кеш-системы.

Для продакшн-версии проекта была выбрана конфигурация Nginx + php-fastcgi + xcache. Время генерации закешированной страницы листинга описанного примера было около 0.1 сек на свободном сервере.
Ну мне, к сожалению, кеш применять особенно негде было, так… игрался…
Все впереди.
Можно конфигурацию сервера, действительно интересно сравнить с нашими результатами
Да, спасибо что поправили.
Кешеры запросов действительно существуют, и это хорошо если они вам больше подходят под ваши задачи. В нашем проекте самым выгодным оказалось html-кеширование.
спасибо за статью, очень интересный подход к кэшированию.

У меня возник вопрос про удаление данных из кэша,
Вы писали $cacheManager->remove('@sf_cache_partial?module=index&action=_listingBlock&sf_cache_key=*');
Можно ли мы как-то вычислить sf_cache_key, чтобы удалить конкретный элемент из кэша?
Кстати хороший вопрос для тех, задумывается о динамичном управлении кешем.

За создание html-кеша отвечает класс sfViewCacheManager, а именно его метод:

sfViewCacheManager::generateCacheKey($internalUri, $hostName = '', $vary = '', $contextualPrefix = '')

В этом методе происходит получение передаваемых в компонент параметров из контекста, и для них вызывается метод sfViewCacheManager::convertParametersToKey($params). Хеш ключа вычисляется в методе sfViewCacheManager::computeCacheKey, где делается так:

return md5(serialize($parameters));

Соответственно, чтобы воспроизвести ключ кеша для определенного компонента или партиала, необходимо подать все эти параметры в метод computeCacheKey.

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

Именно поэтому максимальное зло — передавать параметром компонента комбинированный массив из тучи параметров, выбранных из разных таблицы join'ами, а не обычный объект модели.
В каждый партиал или компонент можно передавать с параметрами sf_cache_key. В этом случае ключ не генерируется, генерируете его вы сами.

Или вы можете переопределить обработчик генерации ключей. В settings.yml сразу после .settings определить параметр cache_namespace_callable.

Например
cache_namespace_callable: [«CacheGenerator», «generateCacheKey»]
> $cacheManager->remove('@sf_cache_partial?module=index&action=_listingBlock&sf_cache_key=*');

Лучше не использовать звездочки (*) при чистке кэша при условии использования memcache. Так как при удалении со звездочкой используется метод removePattern, который проходит по всем ключам из кэша и удаляет нужные по маске. Так вот хранятся эти все ключи там же в memcache в отдельной записи [prefix]_metadata c expire равной 0. Может случится ситуация, когда объем записи превысит лимит. ( у меня случилось к слову ) А дальше у сами додумайте ).

Отключить сохранение ключей в одну запись можно параметром:

storeCacheInfo: true

В версия symfony < 1.2.9 эти ключи добавлялись даже без удаления дубликатов:
protected function setCacheInfo($key)
 {
  $keys = $this->memcache->get($this->getOption('prefix').'_metadata');
  if (!is_array($keys))
  {
   $keys = array();
  }
  $keys[] = $this->getOption('prefix').$key;
  $this->memcache->set($this->getOption('prefix').'_metadata', $keys, 0);
 }


* This source code was highlighted with Source Code Highlighter.


Сейчас ситуация лучше, ключи удаляются:
protected function setCacheInfo($key, $delete = false)
 {
  $keys = $this->memcache->get($this->getOption('prefix').'_metadata');
  if (!is_array($keys))
  {
   $keys = array();
  }

  if ($delete)
  {
    if (($k = array_search($this->getOption('prefix').$key, $keys)) !== false)
    {
     unset($keys[$k]);
    }
  }
  else
  {
   if (!in_array($this->getOption('prefix').$key, $keys))
   {
    $keys[] = $this->getOption('prefix').$key;
   }
  }

  $this->memcache->set($this->getOption('prefix').'_metadata', $keys, 0);
 }


* This source code was highlighted with Source Code Highlighter.
storeCacheInfo: false — отключает )
Очень полезный коммент кстати. Спасибо большое!
> При применении ORM в симфони по умолчанию не предусмотрено кеширование самих запросов. Это не потому, что разработчики глупые, а потому, что тут используется кеш другого уровня. Другая идея.

Это верно для Пропела, но не для Doctrine. Который объективно лучше на порядок. Один раз попробовал — больше с Пропелом связываться не хочу :)
Здравствуйте, Дмитрий; )

Я и не отмечал, что никакие дргугие орм не умеют кешить запросы. Видимо, неправильно построил предложение. Смысл в том, что заложенная изначально идеология кеширования — другая. Не кешируют они сами запросы, но кешируют куски хтмл. Это не плюс и не минус, это по-другому. HongKilDong комментом выше это тоже заметил кстати.
Привет, Олег :)

Ага, тот коммент я сразу не заметил. Кэширование ХТМЛ наверное побыстрей будет, поскольку до ОРМ-а в этом случае дело не доходит вообще.

А вообще, за статью — респект. У меня тоже сейчас актуален вопрос высоких нагрузок.
Sign up to leave a comment.

Articles