Doctrine ORM имеет встроенный кэш-менеджер, который умеет кэшировать в
- Memcached
- APC
- DataBase (видимо имеется в виду некая плоская БД с быстрым доступом, типа SQLite)
Узнав сей факт решил воспользоваться встроенным механизмом и протестировать механизм кэширования.
Включение кэширования в symfony
Расширяем возможности конфигурации. В config/ProjectConfiguration.class.php добавляем метод конфигурирования Doctrine:
/**
* Конфигурация ORM
* @param Doctrine_Manager $manager
*/
public function configureDoctrine( Doctrine_Manager $manager )
{
if ( extension_loaded( 'memcache' ) )
{
$servers = array(
'host' => 'localhost',
'port' => 11211,
'persistent' => true
);
$cacheDriver = new Doctrine_Cache_Memcache( array(
'servers' => $servers,
'compression' => false
));
$manager = Doctrine_Manager::getInstance();
$manager->setAttribute( Doctrine::ATTR_QUERY_CACHE, $cacheDriver );
$manager->setAttribute( Doctrine::ATTR_RESULT_CACHE, $cacheDriver );
}
}
Итак, если загружено расширение memcached (это подпорка для того чтобы работало без проблем и без кэширования), определяем сервер (серверы), создаем инстанс драйвера кэша. Кэшировать будем запросы Doctrine::ATTR_QUERY_CACHE (разобранные Doctrine-запросы, чтобы не парсить их каждый раз заново) и результаты запросов Doctrine::ATTR_RESULT_CACHE.
Собственно для того чтобы кэшировались запросы придется использовать такую конструкцию:
Doctrine_Query::create() ... ->useQueryCache () ->useResultCache() ... ->execute ();
Вообще говоря, судя по документации Doctrine, прописав атрибуты менеджера мы обеспечиваем себя кэшированием. На самом деле у меня кэширование не заработало пока не использовал в конструкторе запросов use*Cache().
На самом деле это не есть гуд, так как при таком подходе нельзя выключить кэширование сразу и хитрое конфигурирование не убережет нас от падения продуктовой среды, если в ней нет memcached.
Собственно вот. Переходим к тестированию.
Тестирование кэширования
Для того чтобы оценить эффект от кэширования напишем простой таск, который будет в цикле выполнять однотипные запросы, но со случайными параметрами. Создаем класс lib/task/doctrineTestTask.class.php:
class doctrineTestTask extends sfDoctrineBaseTask
{
}
Конфигуратор – без неожиданностей:
protected function configure()
{
$this->briefDescription = 'Test doctrine memcached';
$this->detailedDescription = <<<EOF
Test doctrine memcached
EOF;
}
Тестовый метод:
protected function execute($arguments = array(), $options = array())
{
// макс ID
$q = Doctrine_Query::create()
->select ( "MAX(l.id) as max, MIN(l.id) as min" )
->from ( "Locality l" )
->useResultCache()
->execute ()
->toArray ();
// тестовый цикл
echo ( $start = time() ) . "n";
for( $i = 0; $i < 10000; $i++ )
{
echo "$ir";
// Случайная locality
while( !( $locality ) )
{
$locality = $this->getRandLocality( $q[0]["min"], $q[0]["max"] );
}
// собственно тестовый запрос с несколькими джойнами. Таблицы от тысяч до пости сотни тысяч строк. Для теста сойдут.
$search_query = Doctrine_Query::create()
->select ( "prop.*, loc.*, haskw.*, kw.*" )
->from ( "Property prop, prop.Locality loc, prop.PropertyHasKeyword haskw, haskw.Keyword kw" )
->where ( "loc.lft >= ? AND loc.rgt <= ?", array( $locality->lft, $locality->rgt ) )
->offset ( 10 * rand( 1, 100 ) )
->limit ( 10 )
->useResultCache()
->execute ();
}
echo ( $end = time() ) . "n";
echo "====================================================n" . ($end - $start);
}
getRandLocality() особого значения не имеет (но результат того запроса тоже кэшируем), поэтому с find() пришлось уйти на Doctrine_Query (пока не смотрел как подружить find* с кэшированием).
Для тестирования под win понадобятся memcached dll и MemCacheD Manager.
Результаты тестирования (последовательный запуски – чтобы прокэшировать данные):
Z:homedoctrine-test>symfony doctrine-test 1266870147 1266872222 ==================================================== 2075 Z:homedoctrine-test>symfony doctrine-test 1266872876 1266873507 ==================================================== 631 Z:homedoctrine-test>symfony doctrine-test 1266877034 1266877157 ==================================================== 123 Z:homedoctrine-test>symfony doctrine-test 1266877387 1266877478 ==================================================== 91 Z:homedoctrine-test>symfony doctrine-test 1266878158 1266878233 ==================================================== 75 Z:homedoctrine-test>symfony doctrine-test 1266878598 1266878658 ==================================================== 60 Z:homedoctrine-test>symfony doctrine-test 1266880037 1266880096 ==================================================== 59
Нисходящий тренд на лицо. Первый запуск занял > 2000 секунд (в кэше ничего не было). Повторный запуск оказался в 3 раза быстрее, последующий в 5 раз быстрее. После этого начали подходить к пределу возможностей кэшера и последующие 4 запуска уменьшили время лишь в два раза. Но там не менее, всего с первого запуска скорость выполнения теста уменьшилась более чем в 35 раз.
Состояние memcached:
Memcached Server 1.2.4
Uptime 04:13:26
Items count 13859
Total items 27711 11
Hits 86088
Misses 15994
Used bytes 8695086
Bytes read 4513330164
Bytes writen 4547347068
Max bytes 134217728
Итого, наш тест в памяти memcached занял примерно 8 Мб. Неплохо, неплохо. Готовим memcached на production серверах
3 Comments
Что-то я запутался с этими мемкешами. Вроде как memcache и memcached разные вещи? И doctrine имеет встроенную поддержку memcache. Или я чего-то не понимаю?
https://www.google.ru/#hl=ru&newwindow=1&safe=active&output=search&sclient=psy-ab&q=memcache+%D0%B8+memcached&oq=memcache+%D0%B8+memcached&aq=f&aqi=g1&aql=&gs_l=hp.3..0.415l415l0l986l1l1l0l0l0l0l111l111l0j1l1l0.frgbld.&pbx=1&bav=on.2,or.r_gc.r_pw.r_cp.r_qf.,cf.osb&fp=45ddeb5f6772cf89&biw=1293&bih=855
См. первую ссылку из гугла )
Хм, думал какое-нибудь уведомление на почту должно свалиться, не дождался. =) Спасибо за ответ, я и запутался благодаря этим статьям. Как понял, у нас есть сервер memcached, а вот клиентские библиотеки для php разные: memcache и memcached. И вот читаю статью:
if ( extension_loaded( ‘memcache’ ) ) <– это по коду
А ниже текст "Итак, если загружено расширение memcached"… Даже если и опечатка (или опять непонимание с моей стороны?),то это условие я и вовсе убирал, доктрина мне ошибку вываливала. Собственно, на этом ступор у меня и возник моменте.