Memcached

Материал из Национальной библиотеки им. Н. Э. Баумана
Последнее изменение этой страницы: 18:52, 13 января 2018.
Memcached
Memcached Hostiso.png
Memcached.png
Создатели: Брэд Фитцпатрик
Разработчики: Danga Interactive
Выпущена: 22 May 2003 года; 16 years ago (2003-05-22)
Постоянный выпуск: 1.4.36 / 20 March 2017 года; 2 years ago (2017-03-20)
Состояние разработки: Active
Написана на: C, C++, PHP, Perl, Java
Операционная система: Кросс-платформенное
Тип ПО: Сервис кэширования
Лицензия: BSD
Веб-сайт memcached.org

Memcached — программное обеспечение, предназначенное для кеширования данных в оперативной памяти на основе хеш-таблицы. Memcached хранит в оперативной памяти данные, доступ к которым осуществляется по ключу (имени), с заданным временем жизни.

Применяется он в основном для кэширования кода веб-страниц, результатов запросов к базе данных и тп. Также он мжет быть использован в качестве «не очень надежного» key-value хранилища. Например, в нем можно хранить сессии пользователей, коды капч или счетчик посетителей, находящихся в данный момент на сайте. При этом memcached крайне нетребователен к вычислительным ресурсам: на нагруженной инсталляции процессорное время, использованное им, редко превышает 10%.

В проекции веб-разработки это может помочь так: без кеширования один и тот же код будет генерироваться на сервере заново для каждого посетителя сайта. [Источник 1] На генерацию уходят ресурсы хостинга. Если посетителей становится много, это заметным образом сказывается на производительности системы. С помощью Memcached возможно один раз сгенерировать код сайта и хранить его результат в оперативной памяти, и когда очередной посетитель обратится к сайту, то хостинг, вместо того, чтобы генерировать всё заново, отдаст копию (кеш), хранящуюся в оперативной памяти. Логично, что чем больше нагрузка на сайт, тем больше пользы от Memcached. В итоге, используя кеширующий сервер, можно добиться двух целей сразу:

  1. Ускорение загрузку страниц;
  2. Уменьшение нагрузки на хостинг.

Принцип работы

Memcached обеспечивает доступ к хэшу через простой сетевой протокол, клиентом которого может выступать программа, написанная на произвольном языке программирования (существуют клиенты для C/C++, PHP, Perl, Java и т.п.).[Источник 2]

После установления соединения между клиентом (произвольное приложение, воспользовавшееся услугами одной из клиентских библиотек) и сервером (распределенной системой, состоящей из daemon'ов), клиенту предоставляется возможность выполнять следующие примитивные действия для организации кэширования:

  • set - установить соответствие между ключом и указанным объектом;
  • add - аналогично set, но только при условии, что объекта с таким ключом в кэше нет;
  • replace - абсолютная противоположность add, выполняется только если такой объект в кэше есть;
  • get - получить объект из кэша по указанному ключу;
  • del - удалить ключ.

Для реализации цепочки атомарных операций (при условии конкурентного доступа к memcached со стороны параллельных процессов) используются дополнительные операции: инкремент/декремент значения ключа (incr/decr), дописать данные к значению ключа в начало или в конец (append/prepend), атомарная связка получения/установки значения (gets/cas) и другие.

С помощью клиентской библиотеки есть возможность кэшировать данные в оперативной памяти множества доступных серверов. Распределение реализуется путём сегментирования данных по значению хэша ключа по аналогии с сокетами хэш-таблицы. Клиентская библиотека, используя ключ данных, вычисляет хэш и использует его для выбора соответствующего сервера. Ситуация сбоя сервера трактуется как промах кэша, что позволяет повышать отказоустойчивость комплекса за счет наращивания количества memcached серверов и возможности производить их горячую замену.

В API Memcached есть только базовые функции: выбор сервера, установка и разрыв соединения, добавление, удаление, обновление и получение объекта, а также Compare-and-swap. Для каждого объекта устанавливается время жизни, от 1 секунды до бесконечности. При исчерпании памяти более старые объекты автоматически удаляются. Для PHP также есть уже готовые библиотеки PECL для работы с memcached, которые дают дополнительную функциональность.

По умолчанию memcached использует порт 11211.

Общая схема кэширования

Memcache.png

В общем случае схема кэширования выглядит следующим образом: frontend’у (той части проекта, которая формирует ответ пользователю) требуется получить данные какой-то выборки. Frontend обращается к быстрому как гепард серверу memcached за кэшом выборки (get-запрос). Если соответствующий ключ будет обнаружен, работа на этом заканчивается. В противном случае следует обращение к тяжелому, неповоротливому, но мощному (как слон) backend’у, в роли которого чаще всего выступает база данных. Полученный результат сразу же записывается в memcached в качестве кэша (set-запрос). При этом обычно для ключа задается максимальное время жизни (срок годности), который соответствует моменту сброса кэша.[Источник 3]

Такая стандартная схема кэширования реализуется всегда. Вместо memcached в некоторых проектах могут использоваться локальные файлы, иные способы хранения (другая БД, кэш PHP-акселератора и т.п.) Однако, в высоконагруженном проекте данная схема может работать не самым эффективным образом.

Архитектура

Memcached спроектирован так, чтобы все его операции имели алгоритмическую сложность O(1), т.е. время выполнения любой операции не зависит от количества ключей, которые хранит memcached. Это означает, что некоторые операции (или возможности) будут отсутствовать в нём, если их реализация требует всего лишь линейного (O(n)) времени. Так, в memcached отсутствуют возможность объединения ключей «в папки», т.е. какой-либо группировки ключей, также мы не найдем групповых операций над ключами или их значениями.

Основными оптимизированными операциями является выделение/освобождение блоков памяти под хранение ключей, определение политики самых неиспользуемых ключей (LRU) для очистки кэша при нехватке памяти. Поиск ключей происходит через хэширование, поэтому имеет сложность O(1).

Используется асинхронный ввод-вывод, не используются нити, что обеспечивает дополнительный прирост производительности и меньшие требования к ресурсам. На самом деле memcached может использовать нити, но это необходимо лишь для использования всех доступных на сервере ядер или процессоров в случае слишком большой нагрузки – на каждое соединение нить не создается в любом случае.

Можно сказать, что время отклика сервера memcached определяется только сетевыми издержками и практически равно времени передачи пакета от frontend’а до сервера memcached (RTT). Такие характеристики позволяют использовать memcached в высоконагруженных web-проектов для решения различных задач, в том числе и для кэширования данных.

Потеря ключа

Memcached не является надежным хранилищем – возможна ситуация, когда ключ будет удален из кэша раньше окончания его срока жизни. Архитектура проекта должна быть готова к такой ситуации и должна гибко реагировать на потерю ключей. Можно выделить три основных причины потери ключей:

  1. Ключ был удален раньше окончания его срока годности в силу нехватки памяти под хранение значений других ключей. Memcached использует политику LRU, поэтому такая потеря означает, что данный ключ редко использовался и память кэша освобождается для хранения более популярных ключей.
  2. Ключ был удален, так как истекло его время жизни. Такая ситуация не является фактической потерей, так как пользователь сам ограничил время жизни ключа, но для клиентского по отношению к memcached кода такая потеря неотличима от других случаев – при обращении к memcached ответ - «такого ключа нет».
  3. Отказ процесса memcached или сервера, на котором он расположен. В этой ситуации теряются все ключи, которые хранились в кэше. Несколько сгладить последствия позволяет кластерная организация: множество серверов memcached, по которым «размазаны» ключи проекта: так последствия краха одного кэша будут менее заметны.

Критичность потери данных

Можно разделить данные, которые хранятся в memcached, по степени критичности их потери на:

«Можно потерять». К этой категории относятся кэши выборок из базы данных. Потеря таких ключей не так страшна, потому что можно легко восстановить их значения, обратившись заново к backend’у. Однако частые потери кэшей приводят к излишним обращениям к БД.

«Не хотелось бы потерять». Здесь можно упомянуть счетчики посетителей сайта, просмотров ресурсов и т.п. Хоть и восстановить эти значения иногда напрямую невозможно, но значения этих ключей имеют ограниченный по времени смысл: через несколько минут их значение уже неактуально, и будет рассчитано новое значение.

«Совсем не должны терять». Memcached удобен для хранения сессий пользователей – все сессии равнодоступны со всех серверов, входящих в кластер frontend’ов. Так вот содержимое сессий не хотелось бы терять никогда – иначе пользователей на сайте будет «разлогинивать». Для этого можно дублировать ключи сессий на нескольких серверах memcached из кластера, так вероятность потери снижается.

Текстовый протокол

Текстовый протокол Memcahced является одним из наиболее простых.

Пример текстового протокола

Данный протокол используется во многих приложениях помимо самого Memcahced. Например, через тот же модуль Cache::Memcached можно работать с MemcacheQ, MemcacheDB, а также Tarantool/Box.

Slab

Slab – это механизм управления памятью, предназначенный для более эффективного распределения памяти и устранения значительной фрагментации. Основой этого алгоритма является сохранение выделенной памяти, содержащей объект определенного типа, и повторное использование этой памяти при следующем выделении для объекта того же типа.

Когда вы просите Memcached cохранить значения, он ищет "slab", связанный с этим значением. Slab имеет значения в пределах определенного диапазона размеров. Slab-ы состоят из 1 Мб страниц, которые разбиты на куски одинаковых размеров . Допустим, размер значения 1001 байт; Memcached будет искать slab который содержит значения между 1000 и 2000 байт. Затем он находит страницы с пустым блоком и вставляет значение в этот блок. Обратите внимание, что блок зафиксирован в размере — он ​​должен быть 2000 байт для хранения наибольшего значение для данного slab-а.[Источник 4]

Теперь стала более понятной "объектная модель" распределения памяти в Memcached: slab имеет много страниц, которые имеют много chunk-ов. Каждый блок (chunk) имеет фиксированный размер, основанный на максимальном размере slab-a так, например, slab размером 2000 байт сохранит значения между 1001 и 2000 байт. Старые версии Memcached использовали slab размером на основе степени двойки. Создавались slab-ы размером 1KB, 2KB, 4KB, ..., вплоть до 1 Мб. Если ваш сервер Memcached был полон значений 1001 байта, то эффективность использования памяти составляло 50% (1001/2000) в худшем случае. Если у вас есть равномерное распределение значения размеров, то вы получите 75% эффективности использования памяти (1500/2000). Ваш 600MB Memcached сервер будет иметь только 450MB фактических данных.

Одним из улучшений, которые сделала компания Facebook для Memcached, был переход на меньший экспоненциальный рост slab-ов. Таким образом, есть не так много "отходов" в сохранении значений в chunk-и. Вместо того, чтобы распределения slab-ов составляло 2 ^ n, последнии версии Memcached используют гораздо меньший экспоненциальный рост (1,25 ^ n), так что вы увидите slab-ы размером 1 Кб, 1.25KB, 1.56KB, и т.д. Это означает, что вместо 25% потерь в среднем, должно быть где-то 10%.

Особенности

  • Все данные хранятся в памяти для ускорения чтения-записи.[Источник 5]
  • Максимальная длина ключа по умолчанию составляет 250 байт, а длина значения — 1 Мб.
  • Ключи можно «расширить», воспользовавшись MD5 или SHA512 (в этом случае нехэшированный ключ будет разумно продублировать в значении).
  • Для хранения очень длинных значений есть функция сжатия и/или разбиения на части.
  • Memcached использует алгоритм кэширования LRU.
  • Весь ввод-вывод осуществляется с помощью libevent.
  • Для ускорения работы память выделяется при запуске демона и не освобождается до его остановки.
  • Для борьбы с фрагментацией памяти используется slab allocator.
  • Все операции являются атомарными, есть поддержка compare-and-swap.
  • С Memcached можно работать по UDP.
  • Помимо текстового протокола также существует бинарный.
  • Используется в LiveJournal, Mail.ru, Twitter, Wikipedia, YouTube, Typepad и многих других проектах.

Преимущества

Memcached целесообразно использовать на высоконагруженных проектах или в случаях повышенной нагрузки на MySQL и дисковую подсистему.[Источник 6]

Изначально разработанная создателями LiveJournal для собственных нужд, Memcached к настоящему моменту стала де-факто стандартом в области кэширования и используется огромным количеством высоконагруженных проектов, в том числе YouTube, Facebook, Twitter и многими другими.

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

Использование Memcached на практике в написании приложений ничуть не сложнее, чем в теории. Например, если говорить о PHP, то для доступа к daemon'y достаточно установить соответствующий PECL extension, который предоставит класс Memcached. С помощью его методов осуществляется доступ ко всем возможностям memcached (connect, set, add, get и т.д.). Для многих других языков программирования также существуют API.

Недостатки

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

Ещё Memcached плох тем, что он "съедает" оперативную память: если под него отведено 200Mb, то можно считать, что 200Mb уже нет на хостинге.

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

Не стот забывать о правильном подходе, а именно, про использование функций и классов при работе с данными, создание обёрток при работе с внешним API. Оставляйте возможность быстрого внедрения memcached или иного кеширующего метода в код.

Memcached и СУБД

Многие СУБД предоставляют встроенные средства кэширования, но на практике они умеют кэшировать только результаты запросов, что не всегда является именно тем, что необходимо веб-приложению. СУБД обычно полностью очищают кэш таблицы при каждом изменении данных, что приводит к полной его бесполезности при активном обновлении таблиц.[Источник 8]

Еще один альтернативный вариант кэширования может предоставить http-сервер, в большинстве случаев кэш дублируется несколько раз для каждого процесса PHP, Perl или любого другого используемого языка программирования. Помимо излишних затрат оперативной памяти, такой вариант развития событий еще и снижает эффективность самого кэша.

Memcached и FreeBSD

Чтобы поднять Memcached под FreeBSD, достаточно выполнить следующие шаги.

  1. Ставим бинарный пакет с мемкэшом: pkg_add -r memcached
  2. В /etc/rc.conf пишем: memcached_enable="YES" memcached_flags="-l 127.0.0.1 -m 1024"
  3. Флагами мы говорим Memcached использовать не более 1 Гб памяти, а также принимать соединения только от приложений, запущенных на локалхосте.
  4. Запускаем сервер: /usr/local/etc/rc.d/memcached start
  5. Готово

Memcached и Perl

Для работы с Memcached в скриптах на Perl потребуется модуль Cache::Memcached:

cpan -i Cache::Memcached

Простейший скрипт

Запуск скрипта:

./memcached.pl val = 128

Помимо чисел также можно хранить строки. Для хранения более сложных объектов требуется сериализация. Например, для сохранения массивов и хэшей можно воспользоваться модулем JSON::XS.

Memcached и Memcache

Под Memcached чаще понимают кеширующий сервер, когда как Memcache — это расширение PHP, предназначенное для работы с этим сервером. Хотя, есть и memcached — расширение PHP.[Источник 9]

Различия между этими двумя расширениями небольшие:

  • Memcache старше: его разработка началась в 2004 году. Memcached разрабатывается с 2009
  • Memcache используется много чаще, чем Memcached.
  • Memcache ограниченней Memcached и не использует возможности сервера Memcached в полную силу (поэтому и началась разработка расширения Memcached).
  • Memcache легче и производительней Memcached (судя по заявлениям специалистов, разница порядка 10%)

Поэтому если функционала Memcache хватает (а в большинстве случаев так и бывает), то используйте Memcache, он быстрее и легче. Если нужны дополнительные возможности, Memcached — ваш выбор.

Источники

  1. Что такое Memcached// Sheensay [2017]. URL: https://sheensay.ru/memcached (дата обращения: 21.12.2017).
  2. Memcached// Википедия [2017]. URL: https://ru.wikipedia.org/wiki/Memcached (дата обращения: 21.12.2017).
  3. Кэширование и memcached // habrahabr[2006-2017]. URL: https://habrahabr.ru/post/42607/ (дата обращения: 21.12.2017).
  4. Внутренности Memcache // ruhighload [2017]. URL: https://ruhighload.com/index.php/2013/02/25/slabs-pages-chunks-%D0%B8-memcached/ (дата обращения: 21.12.2017).
  5. Мemcached — это просто!// Записки программиста [2009-2017]. URL: https://eax.me/memcached/#comment-432394490 (дата обращения: 21.12.2017).
  6. Memcache-сервер // Джино хостинг [2003-2017]. URL: https://hosting.jino.ru/price/memcache/ (дата обращения: 21.12.2017).
  7. Что такое Memcached // sheensay [2017]. URL: https://sheensay.ru/memcached (дата обращения: 21.12.2017).
  8. Обзор memcached // insight it [2008-2015]. URL: https://www.insight-it.ru/storage/2008/obzor-memcached/ (дата обращения: 21.12.2017).
  9. Чем отличаются memcached и memcache // sheensay [2017]. URL: https://sheensay.ru/memcached-memcache(дата обращения: 21.12.2017).