Memcached (произносится по-разному: mem-cash-dee или mem-cashed ) — это распределенная система кэширования памяти общего назначения . Он часто используется для ускорения веб-сайтов, управляемых динамическими базами данных , путем кэширования данных и объектов в оперативной памяти , чтобы уменьшить количество операций чтения из внешнего источника данных (например, базы данных или API). Memcached — это бесплатное программное обеспечение с открытым исходным кодом , действующее под лицензией Revised BSD . [2] Memcached работает в Unix-подобных операционных системах ( Linux и macOS ) и Microsoft Windows . Это зависит от библиотеки libevent .
API-интерфейсы Memcached предоставляют очень большую хэш-таблицу , распределенную по нескольким машинам. Когда таблица заполнена, последующие вставки приводят к удалению старых данных в порядке наименее недавно использованных (LRU). [3] [4] Приложения, использующие Memcached, обычно помещают запросы и дополнения в оперативную память, прежде чем вернуться к более медленному резервному хранилищу, например базе данных.
Memcached не имеет внутреннего механизма для отслеживания возможных ошибок. Однако некоторые сторонние утилиты предоставляют эту функцию.
Memcached был впервые разработан Брэдом Фицпатриком для его веб-сайта LiveJournal 22 мая 2003 года. [5] [6] Первоначально он был написан на Perl , затем позже переписан на C Анатолием Воробеем, который затем работал в LiveJournal. [7] Memcached теперь используется многими другими системами, включая YouTube , [8] Reddit , [9] Facebook , [10] [11] Pinterest , [12] [13] Twitter , [14] Wikipedia , [15] и Студии Метод . [16] Google App Engine , Google Cloud Platform , Microsoft Azure , IBM Bluemix и Amazon Web Services также предлагают сервис Memcached через API. [17] [18] [19] [20]
В системе используется клиент-серверная архитектура. Серверы поддерживают ассоциативный массив ключ-значение ; клиенты заполняют этот массив и запрашивают его по ключу. Ключи имеют длину до 250 байт, а размер значений не может превышать 1 мегабайт .
Клиенты используют клиентские библиотеки для связи с серверами, которые по умолчанию предоставляют свои услуги через порт 11211. Поддерживаются как TCP, так и UDP. Каждый клиент знает все серверы; серверы не общаются друг с другом. Если клиент желает установить или прочитать значение, соответствующее определенному ключу, библиотека клиента сначала вычисляет хэш ключа , чтобы определить, какой сервер использовать. Это обеспечивает простую форму сегментирования и масштабируемую архитектуру без общего доступа между серверами. Сервер вычисляет второй хэш ключа, чтобы определить, где сохранить или прочитать соответствующее значение. Серверы хранят значения в оперативной памяти; если на сервере заканчивается оперативная память, он отбрасывает самые старые значения. Таким образом, клиенты должны рассматривать Memcached как временный кэш; они не могут предполагать, что данные, хранящиеся в Memcached, все еще будут там, когда они им понадобятся. Другие базы данных, такие как MemcacheDB , Couchbase Server , обеспечивают постоянное хранилище, сохраняя при этом совместимость протокола Memcached.
Если все клиентские библиотеки используют один и тот же алгоритм хеширования для определения серверов, то клиенты смогут читать кэшированные данные друг друга.
Типичное развертывание включает несколько серверов и множество клиентов. Однако Memcached можно использовать на одном компьютере, выступая одновременно в качестве клиента и сервера. Размер его хеш-таблицы часто очень велик. Он ограничен доступной памятью на всех серверах в кластере серверов в центре обработки данных. Там, где этого требуют большие объемы веб-публикаций с широкой аудиторией, объем может достигать многих гигабайт. Memcached может быть одинаково полезен в ситуациях, когда либо количество запросов к контенту велико, либо стоимость создания определенного фрагмента контента высока.
Большинство развертываний Memcached происходит в доверенных сетях, где клиенты могут свободно подключаться к любому серверу. Однако иногда Memcached развертывается в ненадежных сетях или там, где администраторы хотят контролировать подключающихся клиентов. Для этой цели Memcached можно скомпилировать с дополнительной поддержкой аутентификации SASL . Для поддержки SASL требуется двоичный протокол.
Презентация на BlackHat USA 2010 показала, что ряд крупных общедоступных веб-сайтов оставили Memcached открытым для проверки, анализа, извлечения и изменения данных. [21]
Даже в доверенной организации модель плоского доверия memcached может иметь последствия для безопасности. Для эффективной простоты все операции Memcached обрабатываются одинаково. Клиенты с действительной потребностью в доступе к записям с низким уровнем безопасности в кеше получают доступ ко всем записям в кеше, даже если они имеют более высокий уровень безопасности и у этого клиента нет оправданной необходимости в них. Если ключ кэша можно предсказать, угадать или найти путем исчерпывающего поиска, его запись в кэше может быть получена.
Некоторые попытки изолировать данные настройки и чтения могут быть предприняты в таких ситуациях, как большие объемы веб-публикаций. Ферма внешних контент-серверов имеет доступ для чтения к memcached, содержащему опубликованные страницы или компоненты страниц, но не имеет доступа для записи. Если публикуется новый контент (и его еще нет в memcached), вместо этого на серверы генерации контента, которые не являются общедоступными, отправляется запрос на создание единицы контента и добавление ее в memcached. Затем контент-сервер повторяет попытку получить его и передать наружу.
В феврале 2018 года CloudFlare сообщила, что неправильно настроенные серверы memcached использовались для крупномасштабных DDoS-атак . [22] Протокол memcached через UDP имеет огромный коэффициент усиления , более 51000. [23] Среди жертв DDoS-атак можно назвать GitHub , который был переполнен пиковым входящим трафиком 1,35 Тбит/с. [24]
Эта проблема была устранена в версии Memcached 1.5.6, которая по умолчанию отключила протокол UDP. [25]
Обратите внимание, что все функции, описанные на этой странице, представляют собой только псевдокод . Вызовы Memcached и языки программирования могут различаться в зависимости от используемого API.
Преобразовать запросы на создание базы данных или объектов для использования Memcached очень просто. Обычно при использовании прямых запросов к базе данных пример кода выглядит следующим образом:
функция get_foo ( int userid ) data = db_select ( «SELECT * FROMusers WHERE userid =?» , userid ) возвращает данные
После преобразования в Memcached тот же вызов может выглядеть следующим образом.
function get_foo ( int userid ) /* сначала попробуйте кэш */ data = memcached_fetch ( "userrow:" + userid ) , если данные /* не найдены: запросите базу данных */ data = db_select ( "SELECT * FROM users WHERE userid = ? " , userid ) /* затем сохраняем в кеше до следующего получения */ memcached_add ( "userrow:" + userid , data ) end возвращать данные
Клиент сначала проверит, существует ли значение Memcached с уникальным ключом «userrow:userid», где userid — это некоторое число. Если результат не существует, он будет выбирать из базы данных, как обычно, и устанавливать уникальный ключ с помощью вызова функции добавления Memcached API.
Однако, если бы был изменен только этот вызов API, сервер в конечном итоге получил бы неверные данные после любых действий по обновлению базы данных: «представление» данных в Memcached устарело. Следовательно, помимо создания вызова «добавить», также потребуется вызов обновления с использованием функции установки Memcached.
function update_foo ( int userid , string dbUpdateString ) /* первое обновление базы данных */ result = db_execute ( dbUpdateString ) , если результат /* обновление базы данных успешно: извлекаем данные для хранения в кэше */ data = db_select ( "SELECT * FROMusers WHERE userid =?" , userid ) /* предыдущая строка также может выглядеть как data = createDataFromDBString(dbUpdateString) */ /* затем сохранить в кеше до следующего получения */ memcached_set ( "userrow:" + userid , data )
Этот вызов обновит текущие кэшированные данные, чтобы они соответствовали новым данным в базе данных, при условии, что запрос к базе данных будет успешным. Альтернативным подходом может быть аннулирование кэша с помощью функции удаления Memcached, чтобы последующие выборки приводили к промаху кэша. Аналогичные действия необходимо будет предпринять при удалении записей базы данных, чтобы сохранить правильный или неполный кэш.
Альтернативная стратегия аннулирования кэша состоит в том, чтобы сохранить случайное число в согласованной записи кэша и включить это число во все ключи, которые используются для хранения определенного типа записи. Чтобы сделать недействительными все такие записи одновременно, измените случайное число. Существующие записи (которые были сохранены под старым номером) больше не будут использоваться, и поэтому в конечном итоге срок их действия истечет или они будут переработаны.
function store_xyz_entry ( int key , string value ) /* Получаем случайное число — используйте ноль, если его еще не существует. * Используемое здесь имя ключа произвольное. */ seed = memcached_fetch ( ":xyz_seed:" ), если неseedseed = 0 / * Создайте ключ , используемый для хранения записи, и сохраните его. * Используемое здесь имя ключа также произвольно. Обратите внимание, что «семя» и «ключ» пользователя * хранятся как отдельные части построенной строки hashKey: «:xyz_data:(seed):(key)». * Это не обязательно, но рекомендуется. */ string hashKey = sprintf ( ":xyz_data:%d:%d" , семя , ключ ) memcached_set ( hashKey , значение ) /* «fetch_entry», не показанный, следует логике, идентичной приведенной выше. */ functionvalidate_xyz_cache () exist_seed = memcached_fetch ( ":xyz_seed:" ) / * Создайте другое случайное начальное число */ doseed = rand () до тех пор, пока семя ! = existing_seed /* Теперь сохраните его в условленном месте. Все будущие запросы будут использовать этот номер. * Таким образом, все существующие записи перестанут использоваться и срок их действия со временем истечет. */ memcached_set ( ":xyz_seed:" , семя )