Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Хранение списков с Lists Основы Redis

В Redis удобно работать с простыми строками. Команды get, set, del покрывают большинство нужд среднего проекта. Но что делать, если нужно хранить множество связанных данных?

how_to_put_data

Например, разрабатывается соц. сеть и необходимо хранить список диалогов пользователя в кэше. При этом есть знаменитости, которым пишут сообщения миллионы пользователей. Хранить всю информацию в N ключах нереально, потому что пара таких пользователей будет занимать всю память на сервере. Некоторые разработчики решают этот вопрос предварительной сериализацией списка в JSON или бинарный формат. Такой способ сработает, но имеет несколько минусов:

  • дополнительная логика со стороны приложения, которая может содержать баги
  • меньшая производительность по сравнению с использованием встроенных типов данных Redis
  • отсутствие возможности использовать функции внутри Redis для работы со списком
  • большие расходы на сериализацию/десериализацию при большом размере списка (например, 1 миллион элементов)

Списки в Redis (Lists)

Списки в Redis — это список строк, упорядоченный в порядке вставки. Для абстракции его можно представить как обычный массив в любом языке программирования. Список может содержать более 4 миллиардов элементов. Самая главная особенность списков в Redis — это возможность получать/читать/удалять элементы с начала или конца списка за константное время O(1) даже при общем размере в несколько миллионов.

Запись элементов

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

Имеется пользователь с ID 14, который опубликовал 3 поста: 10, 20, 30

В абстрактном языке программирования массив постов выглядел бы следующим образом: [30, 20, 10]. Идентификаторы упорядочены от старшего к младшему, потому что в ленте отображаются сначала самые последние посты. Выходит, что каждый новый пост добавляется не в конец списка, а в его начало.

Для добавления элемента в начало списка (слева) существует команда lpush key value1 [value2...]. Если списка не существовало до этого, то Redis создаст новый:

127.0.0.1:6379> lpush user:14:recent_posts 10
(integer) 1
127.0.0.1:6379> lpush user:14:recent_posts 20 30
(integer) 3

Команда lpush возвращает количество элементов в списке после вставки.

Получение элементов

Недавние посты пользователя хранятся в кэше. Чтобы достать элементы списка, используется команда lrange key start_index stop_index:

127.0.0.1:6379> lrange user:14:recent_posts 0 -1
1) "30"
2) "20"
3) "10"

Если указать правую границу как -1, то вернется весь список. Обратите внимание, что в Redis все атомарные значения — строки.

Удаление элементов

Пользователь может удалить пост и в этом случае необходимо его также удалить из кэша.

Есть несколько способов удаления элементов. Самый быстрый и рекомендуемый — это удаление первого/последнего элементов списка с помощью команд lpop key, rpop key:

127.0.0.1:6379> lpop user:14:recent_posts
"30"
127.0.0.1:6379> rpop user:14:recent_posts
"10"

lpop удаляет элемент из начала списка и возвращает его. Команда rpop делает то же самое только с конца.

Если количество элементов в списке маленькое, то можно использовать команду lrem key 0 value, которая ищет в списке значение и удаляет его. Команда lrange возвращает указанные элементы списка.

127.0.0.1:6379> lrem user:14:recent_posts 0 120
(integer) 0
127.0.0.1:6379> lrem user:14:recent_posts 0 20
(integer) 1
127.0.0.1:6379> lrange user:14:recent_posts 0 -1
(empty array)

Если элемент не был найден в списке, то возвращается 0. В случае успешного удаления вернется 1. Так как удалился последний элемент в списке, команда lrange вернула пустой массив.

Время жизни

Любой кэш не должен храниться вечно. Добавим время жизни в 1 час на список с последними постами пользователя 14:

127.0.0.1:6379> expire user:14:recent_posts 3600
(integer) 1
127.0.0.1:6379> ttl user:14:recent_posts
(integer) 3598

Резюме

  • списки в Redis — самый предпочтительный способ кэширования упорядоченных данных
  • добавить элементы в список можно с помощью команд lpush, rpush
  • чтение списка осуществляется командой lrange
  • предпочтительное удаление элементов из списка происходит с начала или конца: lpop, rpop. При небольших размерах можно использовать поиск и удаление: lrem
  • любой кэш хранится какое-то время. На список нужно добавить время жизни командой expire

Дополнительные материалы

  1. Redis LPUSH command
  2. Redis LRANGE command
  3. Redis LREM command
  4. Redis LPOP command
  5. Redis RPOP command
  6. Redis EXPIRE command

Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты.

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
900
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно.

  • 130 курсов, 2000+ часов теории
  • 900 практических заданий в браузере
  • 360 000 студентов
Даю согласие на обработку персональных данных, соглашаюсь с «Политикой конфиденциальности» и «Условиями оказания услуг»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff

Используйте Хекслет по максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Даю согласие на обработку персональных данных, соглашаюсь с «Политикой конфиденциальности» и «Условиями оказания услуг»

Изображение Тото

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