Что за бред? зачем его выложили если его нельзя закончить??? Тогда уберите бесплатность курса! Или надо жаловаться администрации сайта на вас? |
Основы
Почему же Redis такой особенный? Какие задачи он решает? На что следует обращать внимание разработчикам? Перед тем, как ответить на все эти вопросы, мы должны понять, чем же все-таки является Redis.
Очень часто Redis описывают как персистентное (то есть сохраняющееся после окончания работы создавшего его процессса - прим. перев.) хранилище данных типа ключ-значение в оперативной памяти. Я не думаю, что это совсем точное определение. Redis, \linebreak действительно, держит все данные в памяти (позже мы вернемся к этому), и он сохраняет данные на диск для обеспечения персистентности. Но он не просто хранилище данных типа ключ-значение. Очень важно разобраться в этом неточном определении, иначе у вас сложится впечатление, что спектр решаемых Redis проблем весьма узок.
Суть в том, что Redis предоставляет пять разных структур данных, только одна из которых собственно и есть структура типа ключ-значение. Понимание этих пяти структур данных, как они работают, какие методы они предоставляют для взаимодействия, и что вы сможете сделать с их помощью, как раз и являются путем к пониманию Redis. Но сначала давайте разберемся с тем, что же означает предоставление структур данных.
Если мы применим эту концепцию к реляционному миру, мы можем сказать, что базы данных предоставляют один тип структур данных - таблицы. Таблицы одновременно сложные и гибкие. Существует очень мало вещей, которые нельзя смоделировать, \linebreak сохранить и которыми нельзя управлять с помощью таблиц. Тем не менее, они не идеальны. А именно, они не на столько простые, или не на столько быстрые, как хотелось бы. Что, если вместо универсальной структуры мы бы использовали специализированные структуры? В этом случае, наверное, найдутся проблемы, которые мы не сможем решить (или, по крайней мере, не сможем решить достаточно хорошо). Однако, в любом случае, мы выиграем на простоте и скорости.
Использование специфичных структур данных для специфичных задач? Разве это не тот подход, который мы постоянно используем при программировании? Вы не используете хеш-таблицы для всех данных программы, то же самое и со скалярными переменными. (Скалярные типы данных: строки, целые числа, дроби, булев тип - прим. перев.) Я считаю, в этом и состоит подход Redis. Если вы работаете со скалярами, списками, или множествами, почему бы не хранить их как скаляры, списки, хеши и множества? Почему проверка на существование должна быть сложнее чем просто вызов exists(key) или медленнее чем O(1) (постоянное время выполнения выражения, которое не зависит от количества записей в хранилище)?
Составные Кирпичики
Базы Данных
Redis использует знакомую всем концепцию базы данных. База данных содержит набор данных. Типичное предназначение базы данных - это группирование всей информации определенного приложения в месте и изоляция ее от других приложений.
В Redis база данных идентифицируется просто числом, которое по умолчанию равняется 0. Если вы хотите сменить базу данных, то вы можете сделать это командой select. В командной строке просто введите select 1. Redis должен ответить сообщением OK и в терминале вы должны увидеть что-то типа redis 127.0.0.1:6379[1]>. Если вы хотите переключиться обратно на базу по умолчанию, просто введите в командной строке select 0.
Команды, Ключи и Значения
Несмотря на то, что Redis больше, чем просто хранилище типа ключ-значение, в его основе каждая из пяти используемых структур данных имеет, как минимум, ключ и \linebreak значение. Очень важно разобраться в том, что такое ключи и что такое значения, перед тем как двигаться дальше.
Ключ - это то, чем мы помечаем части информации. Мы будем пользоваться ключами часто, но пока достаточно знать, что ключ может выглядеть вот так: users:leto. Под таким ключом можно ожидать информацию о пользователе под именем leto. Двоеточие не имеет никакого особого значения, но использование подобных разделителей является хорошим тоном.
Значение - это данные, которые ассоциированы с ключом. Это может быть что угодно. Иногда это строки, иногда числа, а иногда там хранятся сериализованные объекты (в виде JSON, XML или любых других форматов). В основном, Redis рассматривает значение как массив байт и не интересуется тем, что они собой представляют. Обратите внимание, что разные драйверы производят сериализацию по-разному. Поэтому, здесь мы будем говорить только о строках (string), целых числах (integer) и JSON.
Давайте попрактикуемся. Выполните следующие команды:
set users:leto "{name: leto, planet: dune, likes: [spice]}"
Почти все команды Redis выглядят подобным образом. Сначала идет сама команда, в нашем случае set, а потом параметры. Команда set принимает два параметра: ключ, который мы сохраняем, и значение, которое связано с ним. Многие, но не все, команды принимают ключ (это обычно первый параметр). А теперь угадайте, как получить это значение? Надеюсь, что вы догадались (не расстраивайтесь, если это не так):
get users:leto
Попробуйте самостоятельно поиграть с подобными комбинациями. Ключ и значение - это основная концепция, и простейший способ работать с ней - это команды get и set. Создайте других пользователей, попробуйте разные виды ключей и значений.
Запросы
По мере нашего знакомства с Redis, мы поймем две вещи. Ключи это - все, а значения - ничто. Или, другими словами, Redis не позволяет использовать в запросах значения объектов. Из вышесказанного следует, что мы не сможем найти пользователя, который живет на планете dune.
У многих это может вызвать некоторое беспокойство. Мы живем в мире, где запросы к базам данных стали столь гибкие и мощные, что подход Redis кажется примитивным и неудобным. Не дайте ввести себя в заблуждение. Redis не является универсальным решением на все случаи жизни. Существуют проблемы, которые просто не решаются с помощью Redis (из-за ограничений в запросах). Также стоит принять к сведению, что в некоторых случаях, вы найдете другие способы смоделировать ваши данные.
Мы рассмотрим более конкретные примеры в дальнейшем. Сейчас очень важно, чтобы мы разобрались в этих базовых принципах Redis. Этот подход позволяет использовать в качестве значений что угодно - Redis никогда не обращается к ним. Мы научимся строить модели наших данных по-другому, как того требует этот новый мир.
Память и Персистентность
Мы упоминали ранее, что Redis является персистентным хранилищем в оперативной \linebreak памяти. По умолчанию, для поддержания персистентности, Redis сохраняет снимки базы данных на диск в зависимости от того, сколько ключей было изменено. Вы можете \linebreak настроить этот процесс таким образом, что если X - количество изменившихся ключей, то базу данных нужно сохранять каждые Y секунд. По умолчанию, Redis сохраняет базу с интервалами от 60 секунд, если 1000 или более ключей изменились, до 15 минут, если изменились хотя бы 9 ключей.
Кроме того, (или в дополнение к сохранению снимков базы на диске), Redis может быть запущен в режиме дозаписи (append mode). Каждый раз, когда ключ меняется, на диске дописывается запись в файле, открытом в режиме дозаписи (новые записи добавляются в конец файла). Иногда стоит принять риск потери данных последних 60 секунд в случае аппаратной или программной ошибки в обмен на производительность. В других случаях такой риск неприемлем. Redis дает вам выбор. В главе 5 мы рассмотрим третью \linebreak возможность - обеспечение персистентности за счет вспомогательного (slave) хранилища.
Что касается использования памяти, Redis хранит все данные в оперативной памяти. Явным следствием этого является цена использования Redis: оперативная память до сих пор является самой дорогой аппаратной частью серверов.
Я чувствую, что некоторые разработчики забывают о том, как мало места могут занимать данные. Полное собрание сочинений Уильяма Шекспира занимает примерно 5,5 МБ. Что касается масштабирования, другие решения, как правило, ограничены временем ввода/вывода или производительностью процессора. Какое из ограничений (память или ввод/вывод) вынудит вас масштабировать приложение на большем количестве серверов, зависит от типа обрабатываемых данных и от того, как вы их храните и запрашиваете. Пока вы не храните огромные медиа-файлы в Redis, использование оперативной памяти не должно быть проблемой. Для приложений, где это все же будет проблемой, вы, скорее всего, выберете дополнительную нагрузку на ввод/вывод, чем ограничения размера \linebreak памяти.
В Redis была реализована поддержка виртуальной памяти. Тем не менее, эта функция была признана неудачной (самими инженерами Redis) и ее использование не \linebreak рекомендуется.
К слову, 5,5 МБ сочинений Шекспира могут быть сжаты до примерно 2 МБ. Redis не использует автоматическое сжатие, но, поскольку он трактует данные, как набор байт, нет причин, по которым вы не могли бы обменять время обработки на дополнительную память путем сжатия/распаковки данных.
Собираем Все Вместе
Мы коснулись нескольких общих тем. Последнее, что я хотел бы сделать перед \linebreak погружением в Redis, это собрать несколько этих тем вместе. А именно, ограничения запросов, структуры данных и способ хранения данных Redis в оперативной памяти.
Когда вы собираете три эти вещи вместе, вы получаете нечто замечательное - скорость. Некоторые люди думают: "Конечно, Redis быстр, ведь все хранится в памяти". Но это только часть. Настоящая причина, по которой Redis так хорош по сравнению с другими решениями, заключается в его специализированных структурах данных.
Насколько высока скорость? Это зависит от многих вещей: какие команды и типы данных вы используете и так далее. Но производительность Redis обычно измеряется в десятках тысяч или даже сотнях тысяч операций в секунду. Вы можете запустить redis-benchmark (расположен в той же директории, что и redis-server и redis-cli), чтобы проверить это.
Однажды я переписал код, использовавший традиционную модель, для использования Redis. Нагрузочный тест, написанный мной, занимал более 5 минут при использовании реляционной модели данных. Он занял примерно 150 мс с Redis. Вы не всегда будете получать такой значительный прирост, но я надеюсь, что этот пример даст вам \linebreak представление о том, с чем мы имеем дело.
Важно понимать этот аспект Redis, поскольку это влияет на то, как ваше приложение с ним взаимодействует. Разработчики с опытом работы в SQL обычно стараются минимизировать количество обращений к базе данных. Это хороший совет для всех систем, включая Redis. Но, с учетом того, что мы имеем дело с более простыми структурами данных, нам иногда придется обращаться к серверу Redis несколько раз для достижения цели. Такой шаблон доступа к данным может показаться неестественным на первый взгляд, но на самом деле это незначительно по сравнению с получаемой взамен производительностью.
В этой главе
Несмотря на то, что мы лишь немного поиграли с Redis, был рассмотрен широкий спектр вопросов. Не волнуйтесь, если что-то не ясно до конца - как, например, запросы данных. В следующей главе мы перейдем к практике и все ваши вопросы, я надеюсь, найдут ответы.
Ключевые моменты этой главы:
- Ключи - это строки, идентифицирующие фрагменты данных (значения)
- Значения - это произвольные массивы байт, которым Redis не придает никакого смысла
- Redis предоставляет пять специализированных структур данных (он реализован на их основе)
- Все упомянутое вместе делает Redis быстрым и простым в использовании, но не подходящим для любого сценария использования
\clearpage