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