Memcached и Grails. Часть 1: Установка и применение memcached
Команды memcached и оценка производительности кэша
memcached— это распределенная система общего назначения для кэширования данных в памяти. Она разработана компанией Danga Interactive и распространяется под лицензией BSD.
Компания Danga Interactive разработала memcached, столкнувшись с отсутствием системы кэширования в памяти, способной справиться с большим трафиком на сайте компании — LiveJournal.com. Более 20 миллионов просмотров страниц в день представляли огромную нагрузку на базы данных LiveJournal, поэтому Брэд Фицпатрик (Brad Fitzpatrick) из Danga предложил memcached. Применение memcached снизило нагрузку на базы данных этого сайта, а теперь это решение для кэширования используется на многих web-сайтах со значительной нагрузкой по всему миру.
В этой статье сначала будет дан обзор memcached, а затем поэтапно рассмотрен процесс её установки и сборки из исходных текстов в вашей среде разработки. Также вы познакомитесь с командами клиента memcached (их всего девять) и узнаете, как их использовать для стандартных и расширенных операций memcached. В завершение приводится пара приемов для использования команд memcached для измерения производительности и эффективности кэша.
Место memcached в вашей среде
Прежде чем разбираться с установкой и использованием memcached, давайте поговорим немного о том, как memcached может вписаться в вашу среду. Хотя memcached можно использовать где и сколько угодно, я нашел ее наиболее полезной при выполнении нескольких долговременных запросов на уровне базы данных. Зачастую я устанавливаю несколько экземпляров memcached между своими серверами баз данных и серверами приложений и следую простой модели чтения и записи на каждом из этих серверов. Схема на рисунке 1 должна дать представление о настройке архитектуры приложений:
Рисунок 1. Пример архитектуры приложений с memcached

Кликните, чтобы увидеть увеличенное изображение
Эта архитектура очень проста. Имеется Web-слой, куда входят мои экземпляры Apache. Следующий слой — это само приложение. Чаще всего оно работает на Apache Tomcat или каком-нибудь другом сервере приложений с открытым исходным кодом. Следующий слой содержит мои настроенные экземпляры memcached между серверами приложений и серверами баз данных. При использовании конфигурации такого типа чтение и запись в базу данных выполняются немного по-разному.
Чтение
Последовательность, которой я следую при выполнении чтения, такова: берётся запрос (для которого требуется сделать опрос базы данных) с Web-уровня и кэш проверяется на ранее сохраненные результаты этого запроса. Если я нахожу значение, которое ищу, я возвращаю его. Если нет, то я выполняю запрос и сохраняю результаты в кэше, прежде чем вернуть их на Web-уровень.
Запись
При выполнении записи в базу данных сначала необходимо выполнить запись в базу данных, а затем аннулировать все ранее сохраненные результаты, которые будут затронуты этой записью. Эта процедура помогает предотвратить расхождение данных между кэшем и базой данных.
Установка memcached
memcached поддерживает несколько операционных систем, включая Linux®, Windows®, Mac OS и Solaris. В этой статье мы последовательно пройдёмся по всем этапам сборки и установки memcached из исходного кода. Мне нравится собирать из исходных кодов, главным образом потому, что при возникновении каких-то вопросов у меня есть возможность посмотреть на исходный код.
libevent
Единственная зависимость memcached — это libevent, асинхронная библиотека оповещения о событиях. Исходные тексты libevent можно найти на monkey.org. Берите самую свежую версию. В этой статье используется стабильная версия 1.4.11. Получив архив, распакуйте его в подходящее место и выполните команды, приведенные в листинге 1:
Листинг 1. Сборка и установка libevent
cd libevent-1.4.11-stable/ ./configure make make install
memcached
Найдите исходные тексты memcached на Danga Interactive, снова выбрав самую свежую версию. На время написания этой статьи последней была версия 1.4.0. Распакуйте архив tar.gz в удобное место и выполните команды из листинга 2:
Листинг 2. Сборка и установка memcached
cd memcached-1.4.0/ ./configure make make install
После этого у вас должна быть установлена и готова к использованию рабочая копия memcached. Давайте запустим ее и поэкспериментируем.
Использование memcached
Чтобы начать использовать memcached, необходимо, во-первых, запустить сервер memcached, а затем подключиться с помощью клиента telnet.
Для запуска memcached выполняем команду из листинга 3:
Листинг 3. Запуск memcached
./memcached -d -m 2048 -l 10.0.0.40 -p 11211
Эта команда запускает memcached в режиме демона (-d
) с 2 ГБ памяти (-m 2048
), который слушает localhost или порт 11211. Эти значения можно изменить в соответствии с потребностями, но для наших упражнений они хорошо подходят. Следующий шаг — подключение к memcached. Мы подключимся к серверу memcached с помощью простого клиента telnet.
В большинстве операционных систем имеются встроенные клиенты telnet, но если вы используете что-то на основе Windows, вам потребуется загрузить клиент стороннего разработчика. Я рекомендую PuTTy.
После установки клиента telnet выполните команду из листинга 4:
Листинг 4. Подключение к memcached
telnet localhost 11211
Если все прошло хорошо, вы должны получить ответ: Connected to localhost. В противном случае вернитесь назад и убедитесь, что исходные тексты для libevent и memcached были собраны без ошибок.
Теперь мы на сервере memcached. С этого момента с memcached можно общаться с помощью ряда простых команд. Девять клиентских команд memcached можно разбить на три категории:
- Базовые
- Расширенные
- Управление
Базовые команды клиента memcached
Пять базовых команд memcached применяются для простейших операций. Вот эти команды и операции:
set
add
replace
get
delete
Первые три команды — это стандартные команды для внесения изменений, применяемые для манипулирования парами ключ/значение, хранящимися в memcached. Они довольно просты и имеют общий синтаксис, приведенный в листинге 5:
Листинг 5. Синтаксис модифицирующих команд
command <key> <flags> <expiration time> <bytes> <value>
В таблице 1 дается определение параметров модифицирующих команд memcached и их использование.
Таблица 1. Параметры модифицирующих команд memcached
Параметр | Использование |
---|---|
key | Ключ, используемый для поиска кэшированного значения |
flags | Целочисленный параметр, сопровождающий пару ключ/значение; используется клиентом для хранения дополнительной информации о паре ключ/значение |
expiration time | Продолжительность времени в секундах, в течение которого пара ключ/значение должна храниться в кэше (0 — бесконечное время) |
bytes | Количество байт, которое будет храниться в кэше |
value | Хранящееся значение (всегда на второй строке) |
Теперь давайте посмотрим на эти команды в действии.
set
Команда set
добавляет новую пару ключ/значение в кэш. Если этот ключ уже существует, предыдущее значение будет замещено.
Обратим внимание на следующее взаимодействие с использованием команды set
:
set userId 0 0 5 12345 STORED
Если операция set
для пары ключ/значение выполнена успешно, сервер ответит STORED (сохранено). В этом примере в кэш добавлена пара ключ/значение с ключом userId
и значением 12345
. Время окончания действия установлено в 0, это говорит memcached о том, что значение будет храниться в кэше, пока вы его не удалите.
add
Команда add
добавляет в кэш новую пару ключ/значение только в случае, если ключа еще нет в кэше. Если ключ уже существует, предыдущее значение не изменится и вы получите ответ NOT_STORED(не сохранено).
Вот стандартное взаимодействие с помощью команды add
:
set userId 0 0 5 12345 STORED add userId 0 0 5 55555 NOT_STORED add companyId 0 0 3 564 STORED
replace
Команда replace
замещает пару ключ/значение в кэше только в случае, если этот ключ уже существует. Если ключа еще нет в кэше, вы получите от сервера memcached ответ NOT_STORED (не сохранено).
Вот стандартное взаимодействие с использованием команды replace
:
replace accountId 0 0 5 67890 NOT_STORED set accountId 0 0 5 67890 STORED replace accountId 0 0 5 55555 STORED
Последними базовыми командами являются get
и delete
. Значение их вполне очевидно, и синтаксис также сходный:
command <key>
Давайте посмотрим на эти команды в действии.
get
Команда get
используется для извлечения значения, связанного с ранее добавленной парой ключ/значение. Команда get
используется для большинства операций получения данных.
Вот типичное взаимодействие с использованием команды get
:
set userId 0 0 5 12345 STORED get userId VALUE userId 0 5 12345 END get bob END
Как видим, команда get
довольно проста. get
вызывается с ключом, и если этот ключ существует в кэше, будет возвращено значение. В противном случае ничего возвращаться не будет.
delete
Последняя базовая команда —delete
. Команда delete
используется для удаления любых существующих значений в memcached. Команда delete
вызывается с ключом, и если этот ключ существует в кэше, значение будет удалено. В противном случае будет возвращено сообщение NOT_FOUND (не найдено).
Вот взаимодействие клиент-сервер с помощью команды delete
:
set userId 0 0 5 98765 STORED delete bob NOT_FOUND delete userId DELETED get userId END
Расширенные команды клиента memcached
Две расширенные команды, которые можно использовать с memcached, — это gets
и cas
. Команды gets
и cas
предназначены для совместного использования. Эти команды используются вместе, чтобы гарантировать, что существующая пара имя/значение не получит нового значения, если это значение уже обновлено. Давайте взглянем на каждую из этих команд.
gets
Функции команды gets
во многом схожи с функциями базовой команды get
Разница между этими двумя командами состоит в том, что gets
возвращает дополнительный элемент информации: 64-разрядное целое, которое выступает в качестве идентификатора "версии" пары имя/значение.
Вот клиент-серверное взаимодействие с использованием команды gets
:
set userId 0 0 5 12345 STORED get userId VALUE userId 0 5 12345 END gets userId VALUE userId 0 5 4 12345 END
Рассмотрим различия между командами get
и gets
. Команда gets
вернула дополнительное значение — в данном случае целочисленное значение 4, которое идентифицирует пару имя/значение. Если выполнить еще одну команду set
на этой паре имя/значение, дополнительное значение, возвращаемое gets
, изменится, что означает, что пара имя/значение была обновлена. В листинге 6 приводится пример:
Листинг 6. Команда set обновляет спецификатор версии
set userId 0 0 5 33333 STORED gets userId VALUE userId 0 5 5 33333 END
Посмотрите на последнее значение, возвращенное командой gets
. Оно было изменено на 5. Это значение будет меняться каждый раз при изменении пары имя/значение.
cascas
(проверить и установить) — это удобная команда memcached, которая устанавливает значение пары имя/значение только в случае, если эта пара имя/значение не обновлялась с момента последнего выполнения команды gets
. У нее схожий с командой set
синтаксис, но добавлено одно дополнительное значение — то же самое, которое возвращает gets
.
Обратите внимание на следующее взаимодействие с использованием команды cas
:
set userId 0 0 5 55555 STORED gets userId VALUE userId 0 5 6 55555 END cas userId 0 0 5 6 33333 STORED
Как видите, я использовал команду gets
с дополнительным целым 6, и операция отлично выполнилась. Теперь взгляните на последовательность команд в листинге 7:
Листинг 7. Команда cas
со старым спецификатором версии
set userId 0 0 5 55555 STORED gets userId VALUE userId 0 5 8 55555 END cas userId 0 0 5 6 33333 EXISTS
Обратите внимание, что я не использовал самое последнее целое, полученное от gets
, и cas
завершилась неудачно, возвратив значение EXISTS (существует). Фактически совместное использование команд gets
и cas
не позволяет "наступить" на пару имя/значение, которая была обновлена с момента последнего чтения.
Команды управления кэшем
Две последние команды memcached используются для контроля и очистки экземпляра memcached. Это команды stats
и flush_all
.
stats
Команда stats
делает в точности то, что отражает её название: выдает текущую статистику экземпляра memcached, к которому вы подключились. В следующем примере выполнения команд stats
показывается следующая информация о текущем экземпляре memcached:
stats STAT pid 63 STAT uptime 101758 STAT time 1248643186 STAT version 1.4.11 STAT pointer_size 32 STAT rusage_user 1.177192 STAT rusage_system 2.365370 STAT curr_items 2 STAT total_items 8 STAT bytes 119 STAT curr_connections 6 STAT total_connections 7 STAT connection_structures 7 STAT cmd_get 12 STAT cmd_set 12 STAT get_hits 12 STAT get_misses 0 STAT evictions 0 STAT bytes_read 471 STAT bytes_written 535 STAT limit_maxbytes 67108864 STAT threads 4 END
Здесь большинство выходных данных довольно понятны. Смысл этих значений я раскрою более подробно далее в статье, во время обсуждения производительности кэша. А пока что посмотрите на выходные данные и запустите несколько команд set
с новыми ключами, а затем снова запустите команду stats
, обращая внимания на изменения.
flush_allflush_all
— это последняя команда memcached, которую нам нужно выучить. Эта простейшая команда просто удаляет все пары имя/значение из кэша. flush_all
может быть очень полезна, если нужно очистить кэш. Вот пример применения flush_all
:
set userId 0 0 5 55555 STORED get userId VALUE userId 0 5 55555 END flush_all OK get userId END
Производительность кэша
Мы завершим статью уроком по применению расширенных команд memcached для получения сведений о том, насколько хорошо работает кэш. Команда stats
неоценима в настройке работы кэша. Две из самых важных статистических характеристик, за которыми нужно следить, — это get_hits и get_misses. Эти значения показывают, сколько раз пара имя/значение была найдена (get_hits), и сколько раз не найдена (get_misses).
Сочетание этих значений может показать, насколько эффективно используется кэш. Когда кэш только начинает работу, значение get_misses обычно растет, но после какого-то количества обращений число, возвращаемое get_misses, должно снижаться — что показывает, что кэш заполняется наиболее употребительными чтениями. Если окажется, что get_misses продолжает быстро расти, а get_hits выравнивается, нужно посмотреть на то, что вы кэшируете. Возможно, что кэшируется что-то ненужное.
Еще один метод определения эффективности кэширования состоит в том, чтобы взглянуть на коэффициент попаданий в кэш. Этот коэффициент сообщает процентное отношение числа выполнения команд get
к количеству раз, когда get
не находит значения. Чтобы определить это соотношение, вновь выполните команду stats
, как показано в листинге 8:
Листинг 8. Вычисление коэффициента попаданий в кэш
stats STAT pid 6825 STAT uptime 540692 STAT time 1249252262 STAT version 1.2.6 STAT pointer_size 32 STAT rusage_user 0.056003 STAT rusage_system 0.180011 STAT curr_items 595 STAT total_items 961 STAT bytes 4587415 STAT curr_connections 3 STAT total_connections 22 STAT connection_structures 4 STAT cmd_get 2688 STAT cmd_set 961 STAT get_hits 1908 STAT get_misses 780 STAT evictions 0 STAT bytes_read 5770762 STAT bytes_written 7421373 STAT limit_maxbytes 536870912 STAT threads 1 END
Теперь возьмите значение get_hits и разделите его на значение cmd_gets. В этом примере коэффициент равен примерно 71 проценту. В идеале хотелось бы иметь намного более высокий процент — чем больше, тем лучше. Наблюдение за этой статистикой и измерение этих данных с течением времени продемонстрирует эффективность вашей стратегии кэширования.
Заключение к части 1
Кэширование является неотъемлемой частью любого «тяжёлого» web-приложения, и memcached — прекрасный выбор. Я лично много раз добивался успеха, используя ее. Выбрав memcached в качестве решения для кэширования, вы наверняка убедитесь в её эффективности.
Во второй части этой статьи мы рассмотрим интеграцию memcached в Grails-приложение. Это предоставит нам возможность изучить отличный и надежный комплекс инструментов для разработки масштабируемых web-приложений и заняться действительно увлекательной работой. А пока содержимое этой статьи является отличной отправной точкой для дальнейшего освоения memcached. Я рекомендую вам установить свой собственный экземпляр memcached и поэкспериментировать.
Ресурсы для скачивания
Похожие темы
- Оригинал статьи memcached and Grails, Part 1: Installing and using memcached (EN).
- "Распределенное кэширование с помошью Memcached" (Брэд Фицпатрик (Brad Fitzpatrick), Linux Journal, август 2004 г.): Брэд Фицпатрик из Danga Interactive знакомит с memcached.
- "Архитектуры для балансировки серверной нагрузки: Архитектуры транспортного уровня" (Грегор Рот (Gregor Roth), JavaWorld, октябрь 2008 г.): балансировка нагрузки с помощью memcached на основе кэширования сообщений
HttpResponse
по нескольким машинам. - "Вопросы настройки производительности в вашей серверной среде" (Шон Волберг (Sean Walberg), developerWorks, январь 2009 г.): обзор взаимодействия различных компонентов web-приложения, включая общие проблемы производительности и решения, подобные кэшированию.
- "Memcached — хороший или плохой знак для MySQL?" (Гэри Оренштайн (Gary Orenstein), Gigaom.com, май 2009 г.): обзор того, в какие места стека приложения вписывается memcached, и как легковесные альтернативные решения для кэширования бросают вызов СУБД.
- Загрузить memcached: распределенная система кэширования в памяти.
- Загрузить libevent: асинхронная библиотека оповещения о событиях.
- Загрузить PuTTy: telnet-клиент для Windows.