I. Сценарии использования структур данных Redis

Я ранее читал книгу «redisbook» и уже знаком с базовыми возможностями Redis. На прошлой неделе я начал читать исходный код Redis. Текущая цель — досконально разобраться в структурах данных Redis. Как все знают, всего в Redis 5 структур данных. Каковы сценарии использования каждой структуры данных?

  • String — строка
  • Hash — словарь
  • List — список
  • Set — множество
  • Sorted Set — сортированное множество

Ниже мы кратко объясним их соответствующие сценарии использования:

1. String — строка

Структура данных String представляет собой простой тип ключ-значение. Значением может быть не только String, но и число (когда числовой тип может быть представлен с помощью Long, кодировка — integer; в противном случае оно хранится в sdshdr как строка). Используя тип String, можно полностью реализовать текущую функциональность Memcached с более высокой эффективностью. Вы также можете пользоваться планируемым сохранением Redis (с выбором режима RDB или AOF), журналами операций, репликацией и другими возможностями. Помимо предоставления тех же операций get, set, incr, decr и других, что и Memcached, Redis также предоставляет следующие операции:

  • LEN niushuai: O(1) получить длину строки
  • APPEND niushuai redis: Добавить содержимое в строку, при этом используется умное выделение памяти (удвоение каждый раз)
  • Установить и получить фрагмент строки
  • Установка и получение определённого бита строки
  • Пакетная установка содержимого набора строк
  • Атомарный счётчик
  • Умелое использование команды GETSET: установить новое значение, одновременно очищая старое, и использовать её вместе с атомарным счётчиком

2. Hash — словарь

В Memcached мы часто упаковываем некоторую структурированную информацию в хеш-карту, сериализуем её на стороне клиента и сохраняем как строковое значение (обычно в формате JSON), например никнейм пользователя, возраст, пол, баллы и т. д. В этом случае, когда нужно изменить один из этих пунктов, обычно приходится извлекать строку (JSON), десериализовать её, изменять значение этого пункта, затем снова сериализовать в строку (JSON) и сохранять заново. Чтобы изменить всего один атрибут, требуется выполнить так много действий, что это, безусловно, очень затратно и не подходит для ситуаций, где возможны конкурентные операции (например, когда две конкурентные операции должны изменить баллы). Однако структура Hash в Redis позволяет изменять только значение определённого атрибута, как при обновлении атрибута в базе данных.

  • Хранение, чтение и изменение атрибутов пользователя

3. List — список

List — это, откровенно говоря, связанный список (Redis реализует List с помощью двусвязного списка). Любой, кто изучал структуры данных, должен понимать его устройство. Со структурой List мы можем легко реализовать такие функции, как ранжирование последних сообщений (например, TimeLine в Sina Weibo). Другое применение List — в качестве очереди сообщений: можно использовать операции *PUSH для List, чтобы сохранять задачи в List, а затем рабочие потоки с помощью операций POP извлекают задачи для выполнения. Redis также предоставляет API для работы с диапазоном элементов в List, поэтому можно напрямую запрашивать или удалять диапазон элементов в List.

  • Лента Weibo
  • Очередь сообщений

4. Set — множество

Set — это коллекция; понятие коллекции — это сочетание набора неповторяющихся значений. Используя структуру данных Set, предоставляемую Redis, можно хранить некоторые данные коллекционного типа. Например, в приложении Weibo можно хранить всех пользователей, на которых подписан пользователь, в одном множестве, а всех его подписчиков — в другом множестве. Поскольку Redis очень удобно предоставляет для множеств такие операции, как пересечение, объединение и разность, можно очень удобно реализовать функции взаимных подписок, общих интересов и друзей второй степени. Для всех вышеперечисленных операций над множествами можно также использовать разные команды, чтобы выбрать, возвращать результат клиенту или сохранять его в новом множестве.

  • Взаимные друзья, друзья второй степени
  • Используя уникальность, можно подсчитать все уникальные IP-адреса, посещающие сайт
  • При рекомендации друзей находите пересечение по тегам; если оно больше определённого порога, можно сделать рекомендацию

5. Sorted Set — сортированное множество

По сравнению с Set, Sorted Set добавляет к элементам множества параметр веса — score, так что элементы множества можно упорядочить по score. Например, в Sorted Set, хранящем оценки всех одноклассников, значением элемента множества может быть идентификатор студента, а score — их экзаменационная оценка. Таким образом, при вставке данных в множество они уже естественно отсортированы. Кроме того, Sorted Set можно использовать как очередь с весами. Например, обычные сообщения имеют score 1, а важные сообщения — score 2; тогда рабочие потоки могут выбирать рабочие задачи в порядке убывания score, что позволяет важным задачам выполняться первыми.

  • Элементы с весами, например таблица лидеров по очкам пользователей игры
  • Достаточно сложная структура данных, обычно используется не во многих сценариях

II. Другие сценарии использования возможностей Redis

1. Система публикации-подписки

Pub/Sub, буквально понимаемый, — это публикация (Publish) и подписка (Subscribe). В Redis можно настроить публикацию сообщений и подписку на сообщения для определённого ключа. Когда сообщение публикуется на ключе, все подписанные на него клиенты получат соответствующее сообщение. Наиболее очевидное применение этой возможности — система обмена сообщениями в реальном времени, например обычный обмен мгновенными сообщениями, групповой чат и другие функции.

2. Транзакции

Кто сказал, что NoSQL не поддерживает транзакции? Хотя транзакции Redis не обеспечивают строгие ACID-транзакции (например, если серия команд, отправленных на выполнение через EXEC, вызовет падение сервера во время выполнения, то некоторые команды уже будут выполнены, а остальные — нет), транзакции всё же предоставляют базовую функцию упаковки команд для выполнения (когда с сервером нет проблем, они могут гарантировать, что серия команд выполняется последовательно вместе, и никакие команды других клиентов не вставятся между ними). Redis также предоставляет функцию Watch: вы можете Watch ключ, а затем выполнить транзакции. В этом процессе, если наблюдаемое значение изменено, транзакции обнаружат это и откажутся выполняться.