При работе над бэкэндом сколько-нибудь крупного проекта перед разработчиком рано или поздно встает вопрос выбора хранилища. На определенном этапе РСУБД перестает удовлетворять потребности проекта:
- Требование на быструю запись/чтение. При высоких нагрузках скорость ответа от базы растет. РСУБД можно ускорять разными путями: оптимизировать настройки, профилировать и улучшать запросы, шардировать и реплицировать. Однако эти оптимизации все равно не позволят стабильно отвечать на запросы за несколько мс.
- Строгая структура таблиц. Сегодня в любом бизнесе важна скорость доставки ценности до конечного пользователя. Вследствие этого на проектах происходят частые изменения, которые затрагивают схемы таблиц. Сперва может показаться, что это не проблема, но, во-первых, составление миграций занимает время, во-вторых, в таблице может храниться слишком много записей для изменений "в бою".
В вышеперечисленных случаях можно использовать key-value (далее "KV") хранилища.
Redis как key-value хранилище
Рассмотрим стандартный пример использования Redis как KV: хранение информации о сессиях пользователей. Когда пользователь авторизуется на сайте, генерируется идентификатор сессии и используется как ключ. В значении сохранятся идентификатор пользователя (user_id) и любая нужная персональная информация. Обычно сессия записывается в cookie браузера. После этого backend моментально определяет, от какого пользователя пришел запрос.
Запись новой сессии
Попробуем реализовать пример на практике. Представим, что пользователь с идентификатором 120 авторизовался, и серверу нужно создать для него сессию. Обычно идентификатор сессии состоит из большой рандомизированной строки. В данном уроке для простоты будет использоваться числовое представление.
Подключаемся к Redis серверу с помощью redis-cli и записываем значение user_id по ключу сессии:
127.0.0.1:6379> set session:1 120
OK
Команда записи в Redis имеет простую конструкцию:
set ключ значение
Сразу стоит обратить внимание на пару важных моментов:
- в ключах рекомендуется использовать двоеточие как разделитель слов (хотя и встречаются другие подходы к наименованию). В примере с сессией ключ имеет вид
session:{session_id}
. - команда
set
записывает значение как строку. Одиночное слово пишется без кавычек, но предложение придется писать в одинарных или двойных кавычкахset key1 'hello world'
.
Получение существующей сессии
Сессия сформирована и записана в Redis и cookie. Теперь при следующем запросе от клиента сервер увидит сессию и пойдет в Redis, чтобы определить пользователя:
127.0.0.1:6379> get session:1
"120"
Redis вернул строку, так как сессия существовала. Но что будет, если клиент пришлет несуществующую сессию?
127.0.0.1:6379> get session:N
(nil)
Вернется значение (nil)
, означающее отсутствие ключа.
Если необходимо проверить сессию на существование без получения идентификатора пользователя, то используется соответствующая команда:
127.0.0.1:6379> exists session:1
(integer) 1
127.0.0.1:6379> exists session:N
(integer) 0
Если ключ существует, Redis возвращает целое число 1. В противном случае вернется 0.
Удаление сессии
При выходе из аккаунта сессия пользователя должна удаляться:
127.0.0.1:6379> del session:1
(integer) 1
127.0.0.1:6379> del session:N
(integer) 0
Ответ Redis идентичен команде exists
:
- 1, если ключ существовал, и он был успешно удален
- 0, если ключа не было, поэтому ничего не было удалено
Хранение дополнительной информации
Допустим, в сессии нужно хранить не только идентификатор (user_id), но и электронную почту пользователя (email). Для этого достаточно в значение положить JSON-объект, содержащий всю необходимую информацию:
127.0.0.1:6379> set session:1 '{"user_id":120,"email":"test@test.com"}'
OK
127.0.0.1:6379> get session:1
"{\"user_id\":120,\"email\":\"test@test.com\"}"
Этот метод имеет некоторые недостатки:
- логика по конвертированию в JSON выносится на уровень приложения. В следующих уроках мы рассмотрим стандартный тип данных в Redis, который позволяет хранить несколько значений по одному ключу
- для получения одного поля user_id нужно достать весь JSON и декодировать его. В Redis существует модуль RedisJSON для решения этой проблемы. Например, получение поля реализуется одной командой:
127.0.0.1:6379> JSON.GET session:1 .user_id
Резюме
- БД в проекте выбираются под конкретные задачи.
- в Redis все значения хранятся по ключам. Абстрактно можно представить в виде хэш-таблицы или словаря. Из-за этого любое чтение/запись имеет очень высокую производительность. Например, Redis без труда выполняет запрос за 3мс при нагрузке в 5000+ RPS (запросов в секунду).
- в Redis хранятся неструктурированные значения. Если необходимо добавить новое поле в существующую структуру, то изменения вносятся только на уровне кода.
- основные команды для работы со значениями:
set
,get
,del
,exists
.
Дополнительные материалы
Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.