Главная > Теория и практика > memcache vs memcached - сравниваем клиенты для PHP

memcache vs memcached - сравниваем клиенты для PHP

performance

Какой клиент лучше использовать при разработке на PHP - php-memcached или php-memcache? Все зависит от того, какие особенности Вам нужны (неужели?). Давайте сравним в двух аспектах - функциональность и производительность.

Функциональность

Клиентская библиотека php-memcache была разработана еще в 2004 году и сегодня существует уже довольно стабильная версия, которая используется в 99.9% проектах (использующих сервер Memcache). Большим недостатком этой библиотеки является ее ограниченные способности - она реализует только часть протокола мемкеша, и не позволяет использовать его дополнительные возможности (какие именно - чуть ниже).

Библиотека php-memcached была разработана сравнительно недавно, но уже успешно используется на некоторых крупных проектах (например, digg.com - из которого и вышла эта разработка). Самое главное ее преимущество - это полная реализация протокола, в том числе:

  • CAS токены для версионирования ключей
  • Обратные вызовы (callbacks)
  • Метод getDelayed() позволяющий уменьшить время ожидания откладывая фактическое чтение ключей
  • Поддержка бинарного протокола
  • Возможность избежать сериализации используя igbinary

Производительность

Теперь давайте сравним производительность на практике.
Для этого напишем небольшой скрипт, который делает одинаковые операции с обоими клиентами:

<?

$ops = 10000;

$m = new Memcache();
$m->addServer('localhost');

$md = new Memcached();
$md->addServer('localhost', 11211);

echo "Test operations: {$ops}";
echo "<h3>get test</h3>";

$s = microtime(true);
for ( $i = 0; $i < $ops; $i++ ) $m->get( md5(rand(1000, 99999)) );
echo "Memcache: " . ($res['memcache']['set'] = microtime(true) - $s ) . "<br />";

$s = microtime(true);
for ( $i = 0; $i < $ops; $i++ ) $md->get( md5(rand(1000, 99999)) );
echo "Memcached: " . ($res['memcached']['set'] = microtime(true) - $s );

echo "<h3>set test</h3>";

$s = microtime(true);
for ( $i = 0; $i < $ops; $i++ ) $m->set(md5(rand(1000, 99999)), 2);
echo "Memcache: " . ($res['memcache']['get'] = microtime(true) - $s ) . "<br />";

$s = microtime(true);
for ( $i = 0; $i < $ops; $i++ ) $md->set(md5(rand(1000, 99999)), 2);
echo "Memcached: " . ($res['memcached']['get'] = microtime(true) - $s );

echo "<h3>delete test</h3>";

$s = microtime(true);
for ( $i = 0; $i < $ops; $i++ ) $m->delete(md5(rand(1000, 99999)));
echo "Memcache: " . ($res['memcache']['delete'] = microtime(true) - $s ) . "<br />";

$s = microtime(true);
for ( $i = 0; $i < $ops; $i++ ) $md->delete(md5(rand(1000, 99999)));
echo "Memcached: " . ($res['memcached']['delete'] = microtime(true) - $s );

echo "<h3>combined test</h3>";

$s = microtime(true);
for ( $i = 0; $i < $ops; $i++ )
{
	$key = md5(rand(1000, 99999));
	$m->set($key, 2);
	$m->get($key);
	$m->delete($key);
}
echo "Memcache: " . ($res['memcache']['combined'] = microtime(true) - $s ) . "<br />";

$s = microtime(true);
for ( $i = 0; $i < $ops; $i++ )
{
	$key = md5(rand(1000, 99999));
	$md->set($key, 2);
	$md->get($key);
	$md->delete($key);
}
echo "Memcached: " . ($res['memcached']['combined'] = microtime(true) - $s );

Как видно, скрипт просто выполняет основные операции сохранения, чтения и удаления ключей 10 тыс. раз и замерает их время для каждого клиента.

Результаты работы теста

Как видно из графика, производительность клиента php-memcache почти втрое выше, чем php-memcached. Следует учесть, что показатели при работе с бинарным протоколом почти не отличалась по времени от ASCII протокола.

Обновление

Благодаря внимательному читателю этого блога удалось выяснить, что сильные отличия в показателях тестов связаны с конкретными версиями и настройками библиотек. Проверка на других платформах дает отличие в производительности не более 10%.

В качестве вывода следует сказать, что клиент php-memcache лучше использовать, если функционала приложению полностью хватает (лучше, т.к. он быстрее). Если нужны расширенные возможности, то нужно использовать php-memcached. Но в этом случае нужно учесть понижение производительности.

Хотя важно заметить: даже не смотря на трехкратное различие в скорости работы, операции общения с сервером Memcache обычно занимают доли процента от времени исполнения приложения. Различие в скорости работ библиотек может быть заметно только при массовой работе с кешом, или же на огромных объемах данных.

Google Bookmarks Digg I.ua Ru-marks Ruspace Zakladok.net Reddit delicious Technorati Yahoo My Web News2.ru БобрДобр.ru Memori.ru rucity.com

Статьи по теме

  1. Igor Skrynkovskyy
    7 Май 2010 в 18:10 | #1

    Дякую за статтю. Тепер буде стимул і самому розібратися з memcache

  2. 7 Май 2010 в 22:46 | #2

    Я бы добавил еще тест на мультигет

  3. 26 Май 2010 в 18:04 | #3

    Здравствуйте!
    Ваш тест на Ubuntu Netbook Remix:

    Test operations: 10000

    get test
    Memcache: 3.74332213402
    Memcached: 3.32582402229

    set test
    Memcache: 3.64596199989
    Memcached: 2.93430399895

    delete test
    Memcache: 2.82469391823
    Memcached: 3.00117897987

    combined test
    Memcache: 6.8338830471
    Memcached: 7.90108919144

    Разницы в 3 раза не наблюдается.

  4. 26 Май 2010 в 18:07 | #4

    @vasa_c
    Давайте сравним, укажите версии библиотек и самого сервера.

  5. 26 Май 2010 в 18:37 | #5

    @Den Golotyuk
    Ubuntu 9.10
    PHP 5.3.2-dev
    PHP Extension 20090626
    Zend Extension 220090626

    php_memcache version 2.2.5
    php_memcached version 1.0.1
    libmemcached version 0.31

    Memcached 1.2.8

  6. 26 Май 2010 в 18:44 | #6

    memcached 1.4.2
    php-memcache 2.2.5
    php-memacached 1.0.2
    PHP 5.2.11
    libmemcached 0.40

    И того, различия в сервере и версии PHP, что скорее всего не может дать такой разницы. Я попробую провести тесты на других серверах и опубликую результаты.

  7. 26 Май 2010 в 18:46 | #7

    Разве что php-memcached в 1.0.2 значительно ухудшился по сравнению с 1.0.1 :)
    Я тоже постараюсь сегодня проверить на FreeBSD

  8. 26 Май 2010 в 19:01 | #8

    @vasa_c
    Я нашел довольно интересную закономерность. Похоже что результаты тестов сильно искажены внутренней проблемой библиотеки memcached (судя по всему этой конкретной версии). Буду благодарен, если проведете тест на своей сторое: в одном случае соединение устанавливается с IP (127.0.0.1) в другом с доменным именем (localhost).

  9. 26 Май 2010 в 19:33 | #9

    И как меняются ваши результаты в зависимости от этого?
    Я не заметил у себя существенных изменений.

    Кстати, rand() и md5() тяжеловаты, лучше их из тестируемого цикла выкинуть.

    $keys = array();
    for ($i = 0; $i < $ops; $i++) {
    $key = md5(rand(1000, 9999));
    $val = 2;
    $keys[$key] = $val;
    }

    $s = microtime(true);
    #for ( $i = 0; $i set(md5(rand(1000, 99999)), 2);
    foreach ($keys as $key => $val) {
    $m->set($key, $val);
    }
    echo “Memcache: ” . ($res['memcache']['get'] = microtime(true) - $s ) . “”;

    $s = microtime(true);
    #for ( $i = 0; $i set(md5(rand(1000, 99999)), 2);
    foreach ($keys as $key => $val) {
    $md->set($key, $val);
    }
    echo “Memcached: ” . ($res['memcached']['get'] = microtime(true) - $s );

    В этом случае тесты ускоряются практически вдвое.
    Но относительные скорости такие же.

  10. 27 Май 2010 в 10:17 | #10

    FreeBSD 6.3-STABLE
    PHP 5.3.2-dev
    php_memcache 3.0.4
    php_memcached 1.0.1
    libmemcached 0.31
    memcached 1.2.8

    результаты для обоих библиотек снова различаются слабо

  11. 27 Май 2010 в 14:23 | #11

    Извиняюсь за назойливость.
    Написал свой тест - http://blgo.ru/t/blog/090527/mc/

    Memcache Memcached
    set-new 191 174
    set-exists 185 173
    get-exists 177 167
    get-empty 170 159
    delete-exists 182 164
    delete-empty 174 160

    Числа - микросекунды на один запрос.

  12. 27 Май 2010 в 14:27 | #12

    @vasa_c
    Спасибо! Важные результаты, т.к. php-memcached показывает лучшую производительность.

  13. rusk
    8 Сентябрь 2010 в 23:41 | #13

    насчёт локалхоста.

    Тут как-то решил протестить неочевидный момент и наткнулся на то, что кэш MySQL отрабатывал почти вдвое быстрее memcache. Сели с админом копаться, и в итоге пересадили memcache на сокет, чем довольно ощутимо разгрузили сервер. Не в разы, конечно, но разница во времени работы скриптов была хорошая.

  14. chernousov
    16 Сентябрь 2010 в 17:19 | #14

    Учтите, что разработка pecl-memcache брошена, и в связке с memcached-1.4.3+ операция delete всегда ведёт к ошибке.

    88 CLIENT_ERROR bad command line format. Usage: delete [noreply]

    Именно поэтому memcache::delete() всегда на порядок быстрее memcached::delete(), т.к. в случае с memcache он просто тупо не выполняется. Отсюда и огромная разница в тесте combined.

    Касательно остальных сравнений, я также нашёл их неверными. Я проводил тесты на семи версиях memcached 1.2.6, 1.3.3, 1.4.1, 1.4.2, 1.4.3, 1.4.4, 1.4.5, и каждую из них тестировал с pecl-memcache-3.0.4 в сравнении с четырьмя pecl-memcached 1.0.0, 1.0.1, 1.0.2 и 2.0.0. То есть было выполнено 7*4=28 тестов во всех возможных комбинациях перечисленных выше версий (начиная с memcached-1.4.3 все операции delete я отключил). Итог - везде оба экстеншна показывают приблизительно одинаковые скорости, а разницу в сотые доли секунд я списываю на сеть.

    • 16 Сентябрь 2010 в 17:35 | #15

      Спасибо за комментарий, действительно тесты составлены неправильно, как показал дальнейший анализ (это обсуждали выше).

  15. chernousov
    17 Сентябрь 2010 в 00:05 | #16

    P.S.
    Вордпресс сожрал знаки больше и меньше, должно было быть так:
    <88 delete c5c3478127f5e50e49b50a3846afe884 1
    >88 CLIENT_ERROR bad command line format. Usage: delete <key> [noreply]
    Админ, поправьте плиз в моём предыдущем комменте.

  16. Алекс
    30 Сентябрь 2010 в 15:59 | #17

    Заметил очепятку в названии страницы :
    memcache vs memached

    вместо

    memcache vs memcached

  17. 14 Октябрь 2010 в 11:27 | #18

    Привет,

    К сравнению клиентов хотел бы попросить прояснить такой момент (не скорость) - это обработка файловеров:
    В “старом” php-memcache - есть встроенный механизм обработки отваливания половины кеша.
    В php-memcached я такого не нашел.

    Пример:
    Имеем два memcached-сервера (srv1, srv2).

    php-memcache - рапределяет ключи по серверам 50%/50% или в зависимости от веса сервера, но в любом случае получаем объем кеша равный сумме памяти выделенной на обоих серверах.
    При падении srv2, то в первый раз переменные, которые были на srv2 не доступны, беруться из источника, но сам модуль уже видит, что srv2 недоступен и сохранение и последующий get происходит уже только с srv1.
    Т.е. оставшийся сервер “подхватывает” кеш того, кто “упал”.

    php-memcached - рапределяет ключи по серверам 50%/50% или в зависимости от веса сервера, но в любом случае получаем объем кеша равный сумме памяти выделенной на обоих серверах.
    При падении srv2, модуль не меняет алгоритм распределения переменных по серверам, и тем самым получаем половина переменных в кеше (на srv1), а половина - без кеша (srv2 down), и будут без кеша, пока не поднимется srv2.

    Вопрос: это такое различие в идеологии, или я где-то чего-то не досмотрел? и в php-memcached можно реализовать failover?
    Задача - получить большой кеш, который можно расширять путем введения новых memcached-серверов.
    Кто как делает?

    Далее:
    У memcached-сервера есть два режима работы: сингл и репликация.
    Репликация очень приятная вещь в плане возможности получения и сохранения конкретного значения _на любой из серверов_. Либо сохранил на один, получаешь с другого. Также можно частично решить вопрос отказоустойчивости.
    Т.е. по сути я могу сделать группы кеш-серверов:
    с1 - репликация на с2
    с3 - репликация на с4

    с1 и с2 в группе (они хранят одни данные), размер кеша определяется одним сервером.
    с3 и с4 в группе (они хранят одни данные), размер кеша определяется одним сервером.

    Но с1 и с3 - можно использовать как рапределение кеша, в котором объем кеша равен сумме.

    Вопрос: как эту структуру указать модулю php? либо первому либо второму?
    Не нашел. :(

  18. 14 Октябрь 2010 в 11:40 | #19

    @kVn
    Привет, спасибо за обширный вопрос.

    1. Методы распределения ключей, включение и выключение фейл-овера и принцип поведения при падении узлов можно менять настройками:

    http://ua.php.net/manual/en/memcache.ini.php
    http://ua.php.net/manual/en/memcached.setoption.php

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

    2. Лично я никогда не использовал репликацию в Memcache, поэтому опыта в этом нет. Могу только посоветовать задуматься об эффективности этого решения. Вы можете все 4 узла использовать под кеш без репликации. Тогда при падении одного из них Вы потеряете только 25% данных в кеше. Это вызовет скачок нагрузки, с которым обязана справиться Ваша система.

  19. maqk
    30 Октябрь 2010 в 13:33 | #20

    пересадите memcached на udp-порт или сокет

    порадуют как результаты php-memcache относительно ее же на tcp
    а также сведет все плюсы php-memcached на нет относительно php-memcache

  20. Borgius
    2 Ноябрь 2010 в 23:29 | #21

    Добрый день!
    Есть ли в природе версия php_memcacheD.dll ? а то очень тяжело поддерживать 2 эти библиотеки, если разработку ведешь на Windows.

  21. Николай
    11 Ноябрь 2010 в 03:02 | #22

    Вот тут гуру собрались!
    Может кто-нибудь может подсказать как установить mamcacheD на php под windows? Облазил интернет - нет .dll

  22. 22 Январь 2011 в 22:50 | #23

    Отнекропощу на предыдущие камменты.

    dll в природе не нашлась, а скомпилировать под win не вышло (хотя и не очень долго пытались). Поэтому для win написал свой эмулятор - http://blgo.ru/blog/2009/06/08/memcache/ , и по собственной практике работает он стаблильно. Может пригодится ещё кому-нибудь.

  23. 30 Январь 2011 в 03:38 | #24

    Test operations: 10000
    get test
    Memcache: 0.34285402297974
    Memcached: 0.71569895744324
    set test
    Memcache: 0.39891600608826
    Memcached: 0.73352599143982
    delete test
    Memcache: 0.19314312934875
    Memcached: 0.7186918258667
    combined test
    Memcache: 0.55521202087402
    Memcached: 2.1280429363251

  24. Samm
    19 Февраль 2011 в 15:41 | #25

    @chernousov
    Проблема с delete пофикшена в 3.0.5

  25. Алексей
    9 Апрель 2011 в 08:14 | #26

    А как установить php-memcached под gentoo? не получается

  1. 22 Январь 2011 в 19:21 | #1