Doctrine + memcached: использование и тестирование

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 серверах ;)

This entry was posted in Профессиональное and tagged , , , , , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

3 Comments

  1. pacahon
    Posted 2012/03/28 at 3:33 pm | Permalink

    Что-то я запутался с этими мемкешами. Вроде как memcache и memcached разные вещи? И doctrine имеет встроенную поддержку memcache. Или я чего-то не понимаю?

    • Posted 2012/03/29 at 8:39 pm | Permalink

      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

      См. первую ссылку из гугла )

      • pacahon
        Posted 2012/04/06 at 6:11 pm | Permalink

        Хм, думал какое-нибудь уведомление на почту должно свалиться, не дождался. =) Спасибо за ответ, я и запутался благодаря этим статьям. Как понял, у нас есть сервер memcached, а вот клиентские библиотеки для php разные: memcache и memcached. И вот читаю статью:
        if ( extension_loaded( ‘memcache’ ) ) <– это по коду
        А ниже текст "Итак, если загружено расширение memcached"… Даже если и опечатка (или опять непонимание с моей стороны?),то это условие я и вовсе убирал, доктрина мне ошибку вываливала. Собственно, на этом ступор у меня и возник моменте.

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">