Сравнение MemCache и MongoDb для сетевого кэша

Возникла достаточно неординарная идея: виде средства сетевого кеша взять не MemCache, а MongoDb и сравнить их производительность. Но для представления и сравнения показателей этих двух «механизмов кеширования» взяли еще и другие средства, позволяющие ускорить работу нашего App (APC, RamFS, TmpFS, XCache).
В статье приведены данные и графики сравнения этих механизмов с описанием и рассуждением полученных данных и графиков.

Любой большой интернет-ресурс рано или поздно сталкивается с проблемой нагрузок на сервер. Все бы ничего, если у Вас всего один сервер, ну или скажем связка Web-сервер + DB-сервер. В общем, все относительно неплохо, если у Вас всего один фронт-энд (Front-end). Но вот проблемы появляются при увеличении Вашего «зоопарка» серверов! Мало того, что у Вас усложняется иерархия связей Ваших серверов, так у Вас появляются еще такие проблемы как централизированное хранение данных — это касается БД, статических файлов и, конечно же, самих файлов кэша.

На работе мы разрабатываем достаточно крупный интернет-ресурс, который уже давно вышел за рамки одного сервера. Благо пока ограничиваемся web-сервером и DB-сервером. Однако начальство сейчас затеяло новый крупный проект, в котором уже на уровне проектировки и продумывания видна ее сумасшедшая структура. Перед небольшой группой программистов сейчас стоит новая и интересная задача: продумать структуру и иерархию проекта, с размерами которого еще ни один из нас лично не сталкивался ранее. Но речь сейчас не об этом проекте, а о выплывающих из его разработки проблем, а именно основной из них — централизированное хранение кэша.

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

Приступим к основной части статьи, а именно к нашему разбору полетов.
Для сравнения производительности кеширования были выбраны следующие средства кеширования: APC, MemCache, RamFS, TmpFS, XCache, а также (неординарный выбор) достаточно быстрая СУБД MongoDB.

Думаю, что нужно начать с того, как мы устанавливали все эти программы и расширения, и с какими трудностями мы столкнулись.
Все эксперименты производились на системе CentOS с 2Gb памяти и установленным PHP [5.3.6], а для большей справедливости, настройку ни одного пакета не проводили, все было взято «с коробки».

Установка APC [3.1.9]:
Тут все просто и легко. Через pecl устанавливаем пакет и все, APC работает.

Установка memcache [2.2.6]:
Тоже достаточно просто. Также через pecl устанавливаем пакет, а затем отдельно устанавливаем саму программу memcache, т.к. это не расширение, а сторонняя программа, которую необходимо устанавливать отдельно, но это не составляет труда. После установки все чудесно заработало.

Установка RamFS:
Это даже больше создание, чем установка. Делается все тоже очень просто: mount -t ramfs -o size=1024m ramfs /tmp/ramfs, тут мы выделяем 1Gb памяти и монтируем ее как файловую систему в директорию /tmp/ramfs.

Установка TmpFS:
Также, как и в прошлом случае, это создание, а не установка. Создается командой mount -t tmpfs -o size=1024m tmpfs /tmp/tmpfs, по которой видно что мы также выделяем 1Gb памяти и монтируем ее как файловую систему в директорию /tmp/tmpfs.

Заметка:
Основные различия между RamFS и TmpFS, которые нас интересуют, заключаются в следующем: оба метода работают почти одинаково, за исключением того, что при достижении выделенного лимита для RamFS, система не сообщит нам о достижении предела используемого объема и записываемые Вами новые данные будут просто пропадать в никуда, а TmpFS (также при достижении выделенного лимита) выдаст сообщение о нехватке места, при этом более старые данные будут перемещены в swap, то есть будет осуществлены дисковые операции, что собственно нас и не устраивает. Как RamFS так и TmpFS будут обнулены и пропадут при перезапуске системы, поэтому, если Вы хотите использовать их и после перезапуска системы, Вам необходимо поместить в автозагрузку скрипт создания данных разделов заново.


Установка XCache [1.3.1]:
А вот тут начинается уже интересное, с чем мы столкнулись. Установка данного пакета оказалась достаточно праблематичная из-за того, что в системе был установлен еще и PHP 5.2 (а он в системе на данный момент является основным), у XCache большой список зависимостей, вот установка данного пакета и являлась проблематичной из-за необходимости подсунуть ему нужные библиотеки. Но даже на этом проблемы с данным расширением не окончились, так как после установки (а стал он вроде как нормально) во время запуска скрипта с тестом для проверки корректности работы данного расширения возникли новые проблемы, заключающиеся в том, что при попытке записи переменной в память возникала ошибка:

Warning: xcache_set(): xcache.var_size is either 0 or too small to enable var data caching in /usr/local/php5.3/xcache.php on line 6

а следом за ней была следующая:

Warning: xcache_get(): xcache.var_size is either 0 or too small to enable var data caching in /usr/local/php5.3/xcache.php on line 10

Спустя 2 дня борьбы с данной ошибкой при помощи прямых рук, клавиатуры и бубна, результат был нулевой. Были догадки что неверно собрана *.so, однако замена нами собранной *.so на скачанную с интернета той же версии ни к чему не привела. В ход пошел дядя Гугль, была найдена точно такая же проблема StackOverflow. Однако решение данной проблемы так и не нашли, поэтому вынуждены были проводить дальнейшие тесты без XCache. Особого разочарования не было, потому что ранее проводимые тесты показали, что разница между APC и XCache почти незначительна, однако проблем с XCache гораздо больше.

Установка MongoDB [1.8.1]:
Установка Mongo достаточно простое и описывать его процесс не стану, однако запуск с необходимой нам конфигурацией приведу:
/usr/local/mongodb/bin/mongod --dbpath /usr/local/mongodb/data --profile=0 --maxConns=1500 --fork --logpath /dev/null --noauth --diaglog=1 --syncdelay=0
Основной параметр, который нас интересует, это последний "--syncdelay=0", который указывает время синхронизации данных, находящихся в памяти с данными на HDD. Указанное значение 0 говорит о том, что мы явно запрещаем Mongo синхронизацию с HDD, данная возможность описывается создателями СУБД, однако не рекомендуется по причине того, что при любом скачке электричества или другом сбое системы, которые могут затронуть демона Mongo, все Ваши данные будут утеряны. Нас данный риск устраивает вполне, т.к. хотим попробовать использовать данную СУБД в качестве кеширующего механизма.

Вроде все установлено и «настроено», теперь приступаем непосредственно к самим тестам.

Для большей честности будем проводить тесты с 4-мя сохраняемыми объемами данных: 4Kb, 72Kb, 144Kb, 2.12Mb.

Рассмотрим полученные данные на графиках:

4Kb:
image
Как видно на 1-ом графике (График времени записи 4Kb данных) — MemCache показал худший результат, после него идут RamFs и TmpFs, затем Mongo и APC.

image
На 2-м графике (График времени чтения 4Kb данных) отчетливо видно как Mongo пасет задних, в то время как MemCache почти сравним с RamFs и TmpFs, которые почти совпали, просто на данном графике расхождения между ними почти незаметны.

72Kb:
image
С 3-го графика (График времени записи 72Kb данных) видно как неадекватно себя повел MemCache, а Mongo вполне предсказуемо. Очень удивительно, что APC, RamFs и TmpFs почти совпали.

image
А вот чтение, отображенное на 4-м графике (График времени чтения 72Kb данных): Mongo сдал позицию и пропустил своего конкурента MemCache вперед, как и ранее APC — лидер всей гонки.

144Kb:
image
Начиная с 5-го графика (График времени записи 144Kb данных) мы видим уже странное поведение почти всех систем — MemCache очень нестабильно себя ведет и иногда на меньшем кол-ве итераций время даже выше чем на большем, а еще удивительней то, что ближе к 500 итерациям Mongo начинает обгонять APC! RamFs и TmpFs держат удивительно высокую планку в скорости.

image
На 6-м графике (График времени чтения 144Kb данных) Mongo всем проигрывает, а APC самый шустрый.

2.12Mb:
image
На 7-м графике (График времени записи 2.12Mb данных), Mongo оказался очень стабильным, однако последняя итерация в 500 раз выбила его из колеи, но он удержался в седле. Конечно обсалютный лидер это APC, а вот с MemCache, TmpFs и RamFs происходит нечто интересное, что будет описанно ниже.

image
На последнем графике (График времени чтения 2.12Mb данных) также очень чудная картина: TmpFs вышел самый медленный, а RamFs самый быстрый. Еще один удивительный момент, что Mongo обошел APC!

Если посмотреть на последние итерации последних 2-х графиков, в которых кешировались файлы по 2.12Mb 500 раз, можно заметить достаточно интересную вещь, что 500 (кол-во итераций) * 2.12 (размер одного файла) = 1`060Mb, что говорит нам о том, что в RamFS и TmpFS мы вышли за предел максимального объема! Поэтому и цифры достаточно интересные и непредсказуемые.
На самом деле все вышло как раз предсказуемо: при достижении верхнего лимита (а у нас это 1024Mb) RamFS просто перестает записывать данные и игнорирует команды на запись. При чтении этих данных физически чтение не происходит, а просто возвращает пустую строку (при обработке на PHP строка не пустая, а интерпретируется как null), а TmpFS в это время ведет себя как раз наоборот — он все наши данные записывает, предварительно выделяя для них место, передвигая более старые данные в swap. Этим и объясняется то, что при таких объемах и подобных кол-вах итераций RamFS занимает достаточно малое время на обработку записи и еще менее — на чтение несуществующих данных, а TmpFS наоборот сильно увеличивает это время из-за необходимости совершать дисковые операции.
Как я указывал выше, все средства были взяты «с коробки», настройка данных средств не осуществлялась, поэтому время у memcache равно 0, т.к. записываемый объем одной записи размером в 2.12Mb просто превышает максимальный объем одной хранимой записи в memcache. Для того, чтобы в memcache можно было хранить данные, размер которых более 2.12Mb, необходимо пересобрать сам memcache, но тогда нужно было бы соответственно настраивать и все остальное, но одинаково настроить разные продукты почти не реально, поэтому я позволил себе оставить данный нюанс в таком виде, в каком он сейчас. Возможно это и не верно, однако нас больше интересовало именно поведение всех этих средств в равных условиях — «с коробки».

Глядя на все эти данные каждый разработчик может сделать свой вывод и свои заключения чем и как пользоваться. Мы же сделали свои выводы, которыми и поделимся:
По причине того, что нас интересуют данные тех средств, которые позволяют кешировать по сети, обсудим MemCache и Mongo. Конечно, во многих случаях, как это видно на графиках, MemCache обходит Mongo при чтении, что более релевантней чем запись, в которой Mongo обходит MemCache. Однако если учесть все те возможности, которые нам дает MongoDb, что конечно понятно, ведь это полноценная СУБД со всеми своими возможностями и простотой работой с ней, то те недостатки в скорости, которые показывает Mongo, с легкостью можно перекрыть ее способностью делать сложные выборки и получение нескольких записей (записей кэша) одним запросом. Еще один плюс MongoDb перед MemCache: при правильной и продуманной архитектуре App можно получать закешированные элементы страницы одним запросом, а уже после получения ответа от Mongo анализировать пришедшую информацию и выполнять необходимые действия и кеширование надостающих блоков.

Также можно и продумать систему таким образом, чтобы был многоуровневый кэш: кэш первого уровня (сетевой кэш) MemCache или Mongo, а кэш второго уровня APC или XCache (но тут еще требуются сравнение).

В ближайшем будущем намечается более углубленный анализ и сравнение MemCache и Mongo — сравнение не только затраченного времени, но и затраченного объема памяти с замером нагрузки на процессор и на сервер в целом.

Напоследок хочется указать то, что тесты запускались неоднократно и данные, приведенные в таблицах — это среднее значение из 10-20 повторений тестов.
Приводить табличные данные тестов не стану из-за большого объема.
Метки:
Поделиться публикацией
Похожие публикации
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама
Комментарии 46
  • 0
    Спасибо за интересное сравнение. Давольно давно работаю в связке Mongo + memcached, а вот про ramfs, tmpfs. Есть вопрос: имеет ли смысл в эти разделы загонять статический контент сайта, чтобы на фронтенде уменьшить операции с диском?
    • –2
      Нет, после перезагрузки данные будут утеряны!
      Эти томы очень хорошо подходят для:
      1. если Вы кешируете страницы целиком (скажем на не большей период времени 5-10 сек.)
      2. если Вы используете кеширование самим web-сервером, в примере nginx, который позволяет кешировать ответ скрипта на время, в приделах которого он даже не будет обращаться к Вашему прокси или cgi. В этом случаи очень удобно ложить кэш nginx-а в эти тома (ramfs или tmpfs).
      • 0
        Ну я конечно о временном хранении. + кто мешает копировать из физического диска необходимые статические файлы в эти разделы после каждой перезагрузки. Конечно это вызовет проблемы, поэтому лучше использовать именно для кеша nginx. Буду тестировать у себя. Спасибо
    • 0
      В статье перепутаны tmpfs и ramfs — заголовки и команды монтирования. точно не перепутали дальше в графиках? :)
      • 0
        Спасибо, сейчас подправлю.
        • 0
          Нет, на графиках все верно, RamFS просто не пишет данные, поэтому «самый быстрый», а TmpFS все время swap-пится.
        • 0
          По XCache — вы как-то не правильно бутерброд едите. Мой опыт говорит о безпроблемности xcache и о проблемах с APC :)
          xcache.var_size — какой размер ставили в php.ini?
          • 0
            Пробовали ставить любые и 2Mb и 200Kb, ставили и 0, что снимает ограничения, все по прежнему, не запускался.
            Что касается APC — все очень просто было, быстро и очень просто.
          • 0
            Интересное сравнение, спасибо. Хотя, на мой взгляд стоило бы отдельно сравнивать хранилища с доступом по сети (к примеру, memcache, redis, mongo) и локальные стораджи в памяти ( к примеру, eaccelerator, apc, xcache, ramfs/tmpfs )
            Понятно, что у второй группы нет задержек на работу с сетью, зато у первой есть возможность обслуживать к примеру ферму бэкендов. Несколько иные задачи у этих двух групп…
            • 0
              И самое главное забыли — показать код чтения-записи, которым тестировали, объемы выделенные на каждый кеш-механизм, общий объём памяти сервера (может, они дрались кому вывалиться в своп?).
              • 0
                Я в самой статье писал что на компе стояло 2Gb памяти, а запускались все тесты по очереди, Вы ведь знаете, что APC не уживется с MemCache. Были написаны простые шел скрипты которые запускал php скрипт и подсовывал ему нужный php.ini.
                • НЛО прилетело и опубликовало эту надпись здесь
            • +5
              Очень радует, что mongodb не сильно сливает простым key-value хранилищам. Я считаю, что это офигенный плюс к mongodb.
              • +2
                Я в ужасе. Не осилить сборку xcache и сказать «ну, он вообще глючный» — это круто

                php --version
                PHP 5.2.17 (cli) (built: Feb 8 2011 23:21:31)
                Copyright © 1997-2010 The PHP Group
                Zend Engine v2.2.0, Copyright © 1998-2010 Zend Technologies
                with XCache v1.2.2, Copyright © 2005-2007, by mOo

                Дальше. Я, когда прочитал на графиках «итераций», подумал, может вы их с параллельными запросами спутали? Похоже что нет, не спутали. И тогда возникает вопрос — а что вы вообще меряли? 1 итерация — да у вас дольше соединение устанавливается. На времени меньше секунды вообще полагаться нельзя — у вас же и один прогон теста был, да?)

                Ну и измерение в один поток — очень помогает понять, как себя инструмент ведёт на реальной нагрузке. В общем, очередное исследование ниачом.
                • +1
                  Прогон был не один, я это написал.
                  На счет сборки XCache я привел ссылку, в которой говорится что не одни мы столкнулись с похожей ситуацией и как ее решить не знаем.
                  На счет времени соединения — да, какраз нас интересовало время, которое тратится на получение данных. Живой пример — Вам нужно получить только одну запись из кэша, что будет лучше MemCache или MongoDb? Это нас и интересовало.

                  И на будущее Вам, если Вы заключаете фразу в кавычки, как Вы это сделали в первом предложении, это подразумевает цитату, а я такого не писал.
                  • +1
                    MongoDB — не кешер, а полноценная документо/объекто ориентированная база.
                    Как БД монго быстра, как кешер не очень. Ежу понятно, что простое ключ-значение хранилище будет быстрее чем монго.
                    • –2
                      Так в данных тестах Mongo так и использовалось, как ключ — значение.
                    • НЛО прилетело и опубликовало эту надпись здесь
                      • 0
                        MemCached — это всего драйвер для PHP, а программа называется MemCache.
                      • 0
                        С MongoDB сильно не сталкивался, а вот с hbase (из того же поколения nosql) приходилось, нормальные показатели если использовать нативный java протокол, да и не зря же facebook перешёл с memcache на hbase, но там согласен его дополнительно ещё интересовали моменты о скорости работы с холодным кешем + единый для всех серверов, а отнють не локальный.
                        • 0
                          Чего-чего? На HBase с memcache? Ничего, что первое — база данных, а второе — тупой кэш?
                          • 0
                            www.slideshare.net/cloudera/h-base-in-production-at-facebook-jonthan-grayfacebookfinal

                            glennas.wordpress.com/2011/03/09/hbase-in-production-at-facebook-jonathan-gray-at-hadoop-world-2010/

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

                            По поводу базы данных: тут стоит учитывать, что это key-value база данных, поэтому выборка по ключу достаточно быстро происходит, а вот попытки писать всё в стиле реляционных бд вызывают ооочень большие тормоза.
                            • 0
                              HBase — key-value? С каких пор?

                              Презентация вообще мутная. В частности, там есть «Note that HBase does not actually replace any of these element of the stack, but rather plays an interesting intermediate role between online transactional and offline batch data processing.»

                              Я не знаю как на самом деле обстоит дело в Facebook. Но HBase очень долгое время не отличалась низким временем отклика. Возможно, в последних версиях стало значительно лучше, но, думаю, до memcache все равно очень далеко.
                      • +1
                        основной вопрос заключается в том что:
                        тестирование в 1 поток не дают никакой информации по поводу того, как всё это всё поведёт себя под большой нагрузкой, не упрётесь ли вы в один момент на неприятную ситуацию когда имеется 1000 запросов на обработку, и каждому надо из кеша по 1 записи:
                        1. выполняем их последовательно в 1 поток, выигрывает база1, база2 сливает в 2 раза.
                        2. выполняем их в 10 потоков, база1 сливает в 5 раз, база2 вырывается вперёд.

                        Так что, как было замечено выше, вы тестировали отнють не поведение системы под нагрузкой. Да я и не могу себе представить какую можно создать нагрузку в 1 поток.

                        По поводу установки соединения (сам java разработчик): неужели в php нет никакого пулинга соединения, чтобы не проводить эту тяжёлую операцию для каждого запроса?

                        Каждый раз инициировать новый коннект и говорить про высокие нагрузки в моём понимании неуместно, даже для рест сервисов в этом случае зачастую открывается один физ коннект и в него последовательно долбятся запросы, а вы тут вообще про кешер разговор ведёте.
                        • +3
                          К сожалению, только сейчас прочел статью. Комментаторы почему-то забыли про важные вещи…

                          Вы к монге обращаетесь по _id, верно? А _id имеет индекс, B-tree. Если в хранилище 500 обьектов, то высота дерева равна log(2)(500) = 9 (если оно сбалансировано), а это значит, что на каждый запрос, по индексу будет 9 операций.

                          А если взять среднестатистический кэш в хайлоад проекте? Там миллиарды записей в кэше, для 1 млрд записей, log2(10^9) = 27 (опять же, если оно сбалансировано). Уже операций в 3 раза больше. Сложность выборки из B-tree равна O(logn).

                          А для memcached, который строит hashtable по сути, потому для него сложность всегда O(1). Вы это отлично почувствуете на больших проектах, когда монга начнет стремительно сдавать с ростом количества записей… И медленным будет даже не чтение, а вставка, так как вставка в B-tree дорогая операция по сравнению с hashtable.

                          Ах да, еще есть лимиты по памяти… Вы бы посмотрели какой оверхед у монги при использовании памяти… Очень удивились бы. На 2гб рамы, мемкеш будет держать 1 млрд среднестатистических данных в кэше, реальных данных, а не выдуманных с размером в 2мб, а вот монга держать не будет, ей, скорее всего, под 8гб понадобится (тут без цифр, субьективные данные основанные на опыте работы).

                          Потому по моему мнению, ваши тесты некорректны, они не покажут как себя будет вести монга и мемкэш в реальных условиях.
                      • +1
                        Вчера только увидели что у Mongo не был отключен журнал. Скорее всего без журнала будет быстрее запись.
                        • 0
                          а safe-insert?
                          • 0
                            Что Вы имеете ввиду?
                            • 0
                              драйвер пыха устроен таким образом, что ему можно указать опцию, по которой команда ждет ответа от сервера. Без нее скорость записи увеличивается, но нет проверки что данные реально записались
                              • 0
                                Мы не ждем ответа от сервера о корректной записи кэша, считаем что он его записал корректно.
                                • 0
                                  + это не особенность драйвера, а дополнительная возможность MongoDB. Если у Вас есть какая-то критическая информация, и Вы должны быть уверенны что данные точно попали в БД, то вы юзаете этот флаг, нам он не нужен.
                          • +2
                            а почему не тестировали redis?
                            • 0
                              Мы тестировали те продукты, которыми в данный момент пользуемся.
                              Хотя на продакшене мы и юзаем XCache, на тестовом сервере установить его не вышло.

                              Возможно при дальнейших тестах мы попробуем и его.
                              • +2
                                потестируйте редис и будете приятно удивлены :)
                            • +6
                              По-моему у автора путаница, зачем-то сравниваются PHP in-process кешеры вроде APC, xCache, c key-value хранилищами вроде Memcache, сюда же приплетены RamFS/TmpFS зачем-то.

                              У всех этих вещей различные предназначения: если вам нужен кешер оп-кодов и внтрипроцессный локальный кеш для ваших аппсерверов, используйте APC/xCache. В заголовке вы упоминаете, что вам нужен «сетевой кеш», причём здесь RamFS/TmpFS непонятно без описания того как именно вы планируете их использовать — тесты-то на локальной машине.

                              Из подходящих под определение «сетевого кеша» у вас только Memcache. Поддержу предыдущие коменты — используйте Redis, только вначале разберитесь что же вам всё-таки нужно.
                              • 0
                                Когда начал читать статью думал, что дальше будут какие-то хитрые решения для APC и xCache с php-демоном, который обрабатывает запросы по сети, а RamFS/TmpFS будут монтироваться по сети…
                              • +1
                                Сравнение сетевого кеша, базы данных, файловой системы и локального кешера опкода с возможностью хранения данных! WTF?
                                • 0
                                  Я знаю почему у вас не вышло подружиться с xcache. =) Я докопался до сути: stunpix.com/2011/07/16/1/
                                  • 0
                                    какая прелесть!
                                    Такие вещи решаются красными надписями 72м шрифтом в документации или даже в выдаче перед запуском кешируемого скрипта, но никак не скрытыми неочевидными дефолтными настройками…
                                    • 0
                                      разработчики xcache видимо иного мнения =)
                                  • 0
                                    Ничерта не видно цвета на таких тонких линиях, так сложно сделать их потолще, особенно подписи к ним?
                                    • 0
                                      >>Также можно и продумать систему таким образом, чтобы был многоуровневый кэш
                                      Именно так и рекомендует Facebook уже много лет.
                                      Кроме того, даже трёхуровневую:
                                      1. php $GLOBALS
                                      2. APC
                                      3. медленное сетевое по вкусу.
                                      www.scribd.com/doc/3871729/Facebook-Performance-Caching

                                      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.