Я пытаюсь ответить на два вопроса в окончательном списке:
- Какие основные структуры данных используются для Redis?
- И каковы основные преимущества / недостатки / варианты использования для каждого типа?
Итак, я прочитал, что списки Redis фактически реализованы с помощью связанных списков. Но для других типов я не могу выкапывать какую-либо информацию. Кроме того, если бы кто-то наткнулся на этот вопрос и не получил сводную информацию о плюсах и минусах изменения или доступа к различным структурам данных, у них был бы полный список того, когда лучше всего использовать конкретные типы для ссылки.
В частности, я хочу обрисовать в общих чертах все типы: строку, список, набор, zset и хэш.
О, я до сих пор смотрел на эту статью:
algorithm
data-structures
redis
Homer6
источник
источник
Ответы:
Я попытаюсь ответить на ваш вопрос, но сначала я начну с того, что может показаться странным: если вы не интересуетесь внутренними компонентами Redis, вам не нужно заботиться о том, как типы данных реализованы внутри. Это по простой причине: для каждой операции Redis вы найдете сложность времени в документации и, если у вас есть набор операций и сложность времени, единственное, что вам нужно, - это некоторое представление об использовании памяти (и потому что мы проводим много оптимизаций, которые могут варьироваться в зависимости от данных, лучший способ получить эти последние цифры - провести несколько тривиальных реальных испытаний).
Но так как вы спросили, вот основная реализация каждого типа данных Redis.
Но когда списки, наборы и отсортированные наборы малы по количеству элементов и размеру самых больших значений, используется другое, гораздо более компактное кодирование. Эта кодировка отличается для разных типов, но имеет особенность, заключающуюся в том, что она представляет собой компактный блок данных, который часто вызывает сканирование O (N) для каждой операции. Поскольку мы используем этот формат только для небольших объектов, это не проблема; Сканирование небольшого O (N) -блока является кэш-памятью, поэтому практически очень быстро, и когда слишком много элементов, кодирование автоматически переключается на собственное кодирование (связанный список, хэш и т. д.).
Но на самом деле ваш вопрос был не только о внутренностях, а о том, какой тип использовать для достижения чего? ,
Струны
Это базовый тип всех типов. Это один из четырех типов, но также является базовым типом сложных типов, потому что List - это список строк, Set - это набор строк и так далее.
Строка Redis - это хорошая идея во всех очевидных сценариях, где вы хотите сохранить HTML-страницу, а также когда вы хотите избежать преобразования уже закодированных данных. Например, если у вас есть JSON или MessagePack, вы можете просто хранить объекты в виде строк. В Redis 2.6 вы можете даже манипулировать такого рода объектной серверной стороной, используя сценарии Lua.
Другое интересное использование строк - это битовые карты и, как правило, массивы байтов произвольного доступа, поскольку Redis экспортирует команды для доступа к произвольным диапазонам байтов или даже к отдельным битам. Например, проверьте этот хороший пост в блоге: Быстрые и простые метрики в реальном времени с использованием Redis .
Списки
Списки хороши, когда вы можете коснуться только крайностей списка: около хвоста или около головы. Списки не очень хорошо разбивают на страницы, потому что произвольный доступ медленный, O (N). Поэтому хорошим использованием списков являются простые очереди и стеки, или обработка элементов в цикле с использованием RPOPLPUSH с тем же источником и назначением для «вращения» кольца элементов.
Списки также хороши, когда мы хотим просто создать ограниченную коллекцию из N элементов, где обычно мы получаем доступ только к верхним или нижним элементам, или когда N мало.
наборы
Наборы - это неупорядоченный сбор данных, поэтому они хороши каждый раз, когда у вас есть набор элементов, и очень важно очень быстро проверить наличие или размер коллекции. Еще одна интересная вещь о наборах - это поддержка случайных или случайных элементов (команды SRANDMEMBER и SPOP).
Наборы также хороши для представления отношений, например: «Кто друзья пользователя X?» и так далее. Но другие хорошие структуры данных для такого рода вещей - это отсортированные наборы, как мы увидим.
Наборы поддерживают сложные операции, такие как пересечения, объединения и т. Д., Так что это хорошая структура данных для использования Redis «вычислительным» способом, когда у вас есть данные, и вы хотите выполнить преобразования этих данных для получения некоторого вывода.
Маленькие наборы кодируются очень эффективно.
Хэш
Хэши - это идеальная структура данных для представления объектов, состоящих из полей и значений. Поля хэшей также могут быть атомарно увеличены с помощью HINCRBY. Если у вас есть такие объекты, как пользователи, сообщения в блоге или другие элементы , хэши, вероятно, будут хорошим вариантом, если вы не хотите использовать свою собственную кодировку, такую как JSON или аналогичную.
Однако имейте в виду, что Redis очень эффективно кодирует маленькие хэши, и вы можете попросить Redis атомарно получить, установить или увеличить отдельные поля очень быстро.
Хэши также можно использовать для представления связанных структур данных с использованием ссылок. Например, проверьте реализацию комментариев на lamernews.com.
Сортированные Наборы
Сортированные наборы являются единственными другими структурами данных, кроме списков, которые поддерживают упорядоченные элементы . Вы можете сделать много интересных вещей с отсортированными наборами. Например, вы можете иметь все виды списков Top Something в вашем веб-приложении. Лучшие пользователи по количеству баллов, лучшие посты по количеству просмотров страниц и тому подобное, но один экземпляр Redis будет поддерживать множество операций вставки и get-top-elements в секунду.
Сортированные наборы, как и обычные наборы, можно использовать для описания отношений, но они также позволяют разбивать список элементов на страницы и запоминать порядок. Например, если я помню друзей пользователя X с отсортированным набором, я легко запоминаю их в порядке принятой дружбы.
Сортированные наборы хороши для приоритетных очередей.
Сортированные наборы похожи на более мощные списки, где вставка, удаление или получение диапазонов из середины списка всегда происходит быстро. Но они используют больше памяти и являются O (log (N)) структурами данных.
Вывод
Я надеюсь, что я предоставил некоторую информацию в этом посте, но гораздо лучше скачать исходный код lamernews с http://github.com/antirez/lamernews и понять, как это работает. Многие структуры данных из Redis используются внутри Lamer News, и есть много подсказок о том, что использовать для решения данной задачи.
Извините за грамматические опечатки, у нас полночь, и я слишком устал для просмотра поста;)
источник
В большинстве случаев вам не нужно понимать базовые структуры данных, используемые Redis. Но немного знаний поможет вам сделать компромисс между ЦП и памятью. Это также помогает вам эффективно моделировать ваши данные.
Внутри Redis использует следующие структуры данных:
Чтобы найти кодировку, используемую определенным ключом, используйте команду
object encoding <key>
.1. Струны
В Redis строки называются простыми динамическими строками или SDS . Это небольшая обертка над
char *
которая позволяет хранить длину строки и количество свободных байтов в качестве префикса.Поскольку длина строки сохраняется, strlen является операцией O (1). Кроме того, поскольку длина известна, строки Redis безопасны в двоичном формате. Для строки вполне допустимо содержать нулевой символ .
Строки - самая универсальная структура данных, доступная в Redis. Строка это все из следующего:
long
который может хранить номера. См INCR , ОВЦС , INCRBY и DECRBY команды.chars
,ints
,longs
или любого другого типа данных) , что может позволить эффективно случайному доступ. Смотрите команды SETRANGE и GETRANGE .2. Словарь
Redis использует словарь для следующего:
Словари Redis реализованы с использованием хэш-таблиц . Вместо объяснения реализации я просто объясню конкретные вещи Redis:
dictType
для расширения поведения хеш-таблицы. Эта структура имеет указатели на функции, поэтому следующие операции являются расширяемыми: а) хеш-функция, б) сравнение ключей, в) деструктор ключей и г) деструктор значений.Структура
Set
данных использует словарь, чтобы гарантировать отсутствие дубликатов.Sorted Set
Использует словарь для отображения элемента в его счет, поэтому ZSCORE представляет собой O (1) операции.3. Вдвойне связанные списки
Тип
list
данных реализован с использованием двусвязных списков . Реализация Redis - это учебник прямо из алгоритма. Единственное изменение заключается в том, что Redis сохраняет длину в структуре данных списка. Это гарантирует, что LLEN имеет O (1) сложность.4. Пропустить списки
Redis использует Skip Lists в качестве базовой структуры данных для Sorted Sets. В Википедии есть хорошее введение. В статье Уильяма Пью « Пропустить списки: вероятностная альтернатива сбалансированным деревьям» есть больше деталей.
Сортированные наборы используют как список пропуска, так и словарь. В словаре хранится оценка каждого элемента.
Реализация списка пропусков в Redis отличается от стандартной реализации следующими способами:
5. Список почтовых индексов
Zip-список похож на двусвязный список, за исключением того, что он не использует указатели и хранит данные встроенными.
Каждый узел в двусвязном списке имеет 3 указателя - один прямой указатель, один обратный указатель и один указатель для ссылки на данные, хранящиеся на этом узле. Указатели требуют памяти (8 байт в 64-битной системе), поэтому для небольших списков двусвязный список очень неэффективен.
Список Zip хранит элементы последовательно в строке Redis. Каждый элемент имеет небольшой заголовок, в котором хранится длина и тип данных элемента, смещение к следующему элементу и смещение к предыдущему элементу. Эти смещения заменяют прямые и обратные указатели. Поскольку данные хранятся в строке, нам не нужен указатель данных.
Zip-список используется для хранения небольших списков, отсортированных наборов и хэшей. Сортированные наборы сведены в список, как
[element1, score1, element2, score2, element3, score3]
и сохранены в Zip List. Хэши сведены в список, как[key1, value1, key2, value2]
и т. Д.С помощью Zip-списков вы можете найти компромисс между процессором и памятью. Zip-списки эффективны при использовании памяти, но они используют больше ресурсов ЦП, чем связанный список (или хэш-таблица / список пропусков). Найти элемент в списке почтовых индексов O (n). Вставка нового элемента требует перераспределения памяти. Из-за этого Redis использует эту кодировку только для небольших списков, хэшей и отсортированных наборов. Вы можете настроить это поведение, изменив значения
<datatype>-max-ziplist-entries
и<datatype>-max-ziplist-value>
в redis.conf. Видеть Redis Memory Optimization, раздел «Специальное кодирование небольших агрегированных типов данных» для получения дополнительной информации.В комментарии к ziplist.c превосходен, и вы можете понять эту структуру данных полностью без необходимости читать код.
6. Интеллектуальные сеты
Наборы Int - это причудливое название для "Sorted Integer Arrays"
В Redis наборы обычно реализуются с использованием хеш-таблиц. Для небольших наборов хеш-таблица неэффективна с точки зрения памяти. Когда набор состоит только из целых чисел, массив часто более эффективен.
Набор Int - это отсортированный массив целых чисел. Для поиска элемента используется алгоритм двоичного поиска . Это имеет сложность O (log N). Добавление новых целых чисел в этот массив может потребовать перераспределения памяти, что может стать дорогим для больших целочисленных массивов.
В качестве дальнейшей оптимизации памяти, наборы Int входят в 3 варианта с различными целочисленными размерами: 16 бит, 32 бита и 64 бита. Redis достаточно умен, чтобы использовать правильный вариант в зависимости от размера элементов. Когда добавляется новый элемент, и он превышает текущий размер, Redis автоматически переносит его на следующий размер. Если строка добавлена, Redis автоматически преобразует набор Int в обычный набор на основе хэш-таблицы.
Наборы Int - это компромисс между процессором и памятью. Наборы Int чрезвычайно эффективны в использовании памяти, а для небольших наборов они работают быстрее, чем хеш-таблица. Но после определенного количества элементов время извлечения O (log N) и стоимость перераспределения памяти становятся слишком большими. На основе экспериментов было установлено, что оптимальное пороговое значение для переключения на обычную хэш-таблицу составляет 512. Однако вы можете увеличить это пороговое значение (уменьшать его не имеет смысла) в зависимости от потребностей вашего приложения. Смотрите
set-max-intset-entries
в redis.conf.7. Почтовые Карты
Zip-карты - это словари, сведенные и сохраненные в списке. Они очень похожи на Zip Lists.
Zip-карты больше не используются с Redis 2.6, а небольшие хеш-коды хранятся в Zip-списках. Чтобы узнать больше об этой кодировке, обратитесь к комментариям в zipmap.c .
источник
Redis хранит ключи, указывающие на значения. Ключи могут быть любыми двоичными значениями вплоть до разумного размера (рекомендуется использовать короткие строки ASCII для удобства чтения и отладки). Значения являются одним из пяти собственных типов данных Redis.
Струны
Строка Redis - это последовательность байтов.
Строки в Redis безопасны в двоичном формате (это означает, что они имеют известную длину, не определяемую никакими специальными завершающими символами), поэтому вы можете хранить в одной строке все до 512 мегабайт.
Строки - это каноническое понятие «ключ-хранилище». У вас есть ключ, указывающий на значение, где ключ и значение являются текстовыми или двоичными строками.
Для всех возможных операций со строками, см. Http://redis.io/commands/#string
Хэш
Хэш Redis - это коллекция пар ключ-значение.
Хэш Redis содержит множество пар ключ-значение, где каждый ключ и значение являются строкой. Хэши Redis не поддерживают сложные значения напрямую (т. Е. Вы не можете иметь в поле хеша значение списка или набора или другого хэша), но вы можете использовать поля хеша для указания на другие сложные значения верхнего уровня. Единственная специальная операция, которую вы можете выполнить над значениями хеш-полей, - это атомарный приращение / убывание числового содержимого.
Вы можете рассматривать хэши Redis двумя способами: как непосредственное представление объекта и как способ компактного хранения множества небольших значений.
Прямые представления объектов просты для понимания. Объекты имеют имя (ключ хеша) и набор внутренних ключей со значениями. Смотрите пример ниже, ну, в качестве примера.
Хранение множества небольших значений с использованием хэша - это умная технология хранения больших объемов данных Redis. Когда хеш имеет небольшое количество полей (~ 100), Redis оптимизирует хранение и эффективность доступа ко всему хешу. Оптимизация хранилища небольших хэшей в Redis вызывает интересное поведение: более эффективно иметь 100 хешей с 100 внутренними ключами и значениями, а не 10 000 ключей верхнего уровня, указывающих на строковые значения. Использование хэшей Redis для оптимизации хранилища данных таким способом требует дополнительных затрат на программирование для отслеживания того, где заканчиваются данные, но если ваше хранилище данных основано на строковых значениях, вы можете сэкономить много накладных расходов памяти, используя этот один странный прием.
Для всех возможных операций с хэшами см. Документацию по хешу.
Списки
Списки Redis действуют как связанные списки.
Вы можете вставлять, удалять и просматривать списки либо из заголовка, либо из конца списка.
Используйте списки, когда вам нужно сохранить значения в том порядке, в котором они были вставлены. (Redis дает вам возможность вставлять в любую произвольную позицию списка, если вам нужно, но производительность вставки будет ухудшаться, если вы вставляете далеко от начальной позиции.)
Списки повторного использования часто используются в качестве очередей производителей / потребителей. Вставьте элементы в список, а затем вытолкните элементы из списка. Что произойдет, если ваши потребители попытаются выскочить из списка без элементов? Вы можете попросить Redis дождаться появления элемента и сразу же вернуть его вам, когда он будет добавлен. Это превращает Redis в систему сообщений / событий / заданий / задач / уведомлений в режиме реального времени.
Вы можете атомарно удалять элементы с любого конца списка, что позволяет рассматривать любой список как стек или очередь.
Вы также можете поддерживать списки фиксированной длины (ограниченные коллекции), обрезая свой список до определенного размера после каждой вставки.
Для всех возможных операций со списками, см. Списки документов
наборы
Наборы Redis - это, ну, наборы.
Набор Redis содержит уникальные неупорядоченные строки Redis, где каждая строка существует только один раз для каждого набора. Если вы добавите один и тот же элемент десять раз в набор, он появится только один раз. Наборы отлично подходят для ленивого обеспечения того, что что-то существует хотя бы один раз, не беспокоясь о том, что дубликаты элементов накапливаются и тратят пространство. Вы можете добавлять одну и ту же строку столько раз, сколько хотите, не проверяя, существует ли она уже.
Наборы быстрые для проверки членства, вставки и удаления членов в наборе.
Наборы имеют эффективные операции над множествами, как и следовало ожидать. Вы можете взять объединение, пересечение и различие нескольких множеств одновременно. Результаты могут быть возвращены вызывающей стороне или результаты могут быть сохранены в новом наборе для последующего использования.
Наборы имеют постоянный доступ для проверки членства (в отличие от списков), а Redis даже имеет удобное удаление и возврат случайных элементов («извлечение случайного элемента из набора») или случайный возврат элементов без замены («дайте мне 30 уникальных случайных пользователей») ") или с заменой (" дайте мне 7 карточек, но после каждого выбора положите карточку обратно, чтобы она потенциально могла быть взята снова ").
Для всех возможных операций над наборами см. Документацию по наборам .
Сортированные Наборы
Сортированные наборы Redis - это наборы с заданным пользователем порядком.
Для простоты вы можете представить отсортированный набор как двоичное дерево с уникальными элементами. (Сортированные Redis наборы на самом деле пропустить списки .) Порядок сортировки элементов определяется счетом каждого элемента.
Сортированные наборы все еще наборы. Элементы могут появляться только один раз в наборе. Элемент в целях уникальности определяется его содержимым строки. Вставка элемента «яблоко» с оценкой сортировки 3, затем вставка элемента «яблоко» с оценкой 500 сортировки приводит к получению одного элемента «яблоко» с оценкой 500 сортировки в вашем отсортированном наборе. Наборы уникальны только на основе данных, а не на основе пар (оценка, данные).
Убедитесь, что ваша модель данных опирается на содержимое строки, а не на оценку элемента для уникальности. Счета могут быть повторены (или даже ноль), но, в последний раз, элементы набора могут существовать только один раз для отсортированного набора. Например, если вы попытаетесь сохранить историю каждого входа пользователя в систему как отсортированный набор, сделав счет эпохой входа в систему и значение идентификатором пользователя, вы в конечном итоге сохраните только последнюю эпоху входа для всех своих пользователей. Ваш набор будет увеличиваться до размера вашей пользовательской базы, а не до желаемого размера имен пользователей *.
Элементы добавляются в ваш набор с оценками. Вы можете обновить счет любого элемента в любое время, просто добавьте элемент снова с новым счетом. Результаты представлены двойными числами с плавающей точкой, так что вы можете указать гранулярность высокоточных временных меток, если это необходимо. Несколько элементов могут иметь одинаковую оценку.
Вы можете получить элементы несколькими различными способами. Поскольку все отсортировано, вы можете запросить элементы, начиная с самых низких баллов. Вы можете запросить элементы, начиная с самых высоких баллов («в обратном порядке»). Вы можете запросить элементы по их сортировке в натуральном или обратном порядке.
Для всех возможных операций над отсортированными наборами см. Документацию по отсортированным наборам.
источник