Тип списка в Redis используется для хранения нескольких упорядоченных строк. Каждая строка в списке становится элементом. Список может хранить до 2^32-1 элементов. В Redis вы можете вставлять (push) и извлекать (pop) с обоих концов списка, а также вы можете получить список элементов в указанном диапазоне, получить элементы с указанным индексом индекса и т. д. Список — это относительно гибкая структура данных, которая может играть роль стека и очереди. В реальной разработке он имеет множество сценариев применения.
Тип списка в Redis используется для хранения нескольких упорядоченных строк. Каждая строка в списке становится элементом. Список может хранить до 2^32-1 элементов.
В Redis вы можете вставлять (push) и извлекать (pop) с обоих концов списка, а также вы можете получить список элементов в указанном диапазоне, получить элементы с указанным индексом индекса и т. д. Список — это относительно гибкая структура данных, которая может играть роль стека и очереди. В реальной разработке он имеет множество сценариев применения.
Типы списков имеют следующие характеристики:
Согласно характеристикам двустороннего списка Redis, он также используется для асинхронных очередей. В реальной разработке структура задачи, которую необходимо отложить, сериализуется в строку и помещается в очередь Redis. Другой поток получает данные из этого списка для последующей обработки.
Сценарии использования:
Но с другой стороны, использование Redis List в качестве очереди сообщений также имеет некоторые недостатки, такие как:
Что касается вышеперечисленных недостатков, то представляется, что первый из них (настойчивость) может быть решен в настоящее время. Во многих компаниях есть команды, которые ведут вторичную разработку на базе Rocksdb Leveldb и внедряют хранилище kv, поддерживающее протокол Redis. Эти магазины уже не Redis, но они почти такие же, как Redis. Они могут обеспечить постоянство данных, но ничего не могут сделать с другими недостатками, упомянутыми выше.
Фактически, в Redis 5.0 добавлен новый тип данных Stream. Это структура данных, специально разработанная для использования в качестве очереди сообщений. Она основана на многих конструкциях Kafka, но есть еще много проблем... Не правда ли, было бы неплохо напрямую. войти в мир Кафки?
До версии Redis3.2 список Redis использовал две структуры данных в качестве базовой реализации:
Redis3.2 сначала сохраняет его в ZipList, а затем преобразует в список LinkedList, если он не соответствует требованиям хранения ZipList. Когда объект списка одновременно удовлетворяет следующим двум условиям, объект списка сохраняется с использованием ZipList, в противном случае он сохраняется с использованием LinkedList.
После версии Redis3.2 список Redis использует структуру быстрого связанного списка QucikList в качестве базовой реализации.
До версии Redis3.2 сжатые списки были не только одной из базовых реализаций List, но также одной из базовых реализаций типов данных Hash и ZSet.
Ziplist — это непрерывное пространство памяти (как и непрерывный массив памяти, но каждый элемент имеет разную длину). Ziplist может содержать несколько узлов (записей). Элементы хранятся рядом друг с другом без лишних промежутков.
Суть сжатого списка — это массив, но к нему добавляются только «длина списка», «смещение хвоста», «количество элементов списка» и «идентификатор конца списка». Это поможет быстро найти начало и конец списка. Хвостовой узел. Сжатый список хранит каждый элемент таблицы в непрерывном адресном пространстве. Каждый элемент использует кодировку переменной длины, поскольку он занимает разное пространство. Поскольку память распределяется последовательно, обход выполняется быстро.
Когда объем данных в нашем списке относительно невелик, а хранимые данные легкие (например, небольшие целочисленные значения, короткие строки), Redis выполнит базовую реализацию, сжимая список.
+--------+--------+--------+-------+----+--------+-------+
| zlbytes| zltail | zllen | entry1 | .. | entryN | zlend |
+--------+--------+--------+-------+----+--------+-------+
свойство | иллюстрировать |
---|---|
“zlbytes” | Представляет длину сжатого списка (включая все байты). |
“zltail” | Указатель (смещение), представляющий конец сжатого списка. |
“zllen” | Представляет количество узлов (Entry) в сжатом списке. |
“entry” | Область хранения может содержать несколько узлов, и каждый узел может хранить целые числа или строки. |
“zlend” | Указывает конец списка |
Если вы хотите найти первый или последний элемент, вы можете быстро получить его через элементы заголовка «zlbytes» и «zltail_offset», а сложность равна O (1). Но при поиске других элементов это не так эффективно. Вы можете искать только по одному. Например, сложность записиN равна O(N).
LinkedList — это стандартный двусвязный список. Узел Node содержит указатели prev и next, которые указывают на узлы-преемники и предшественники соответственно. Таким образом, начиная с любого узла в двусвязном списке, вы можете легко получить доступ к его предшественникам и узлам-преемникам.
LinkedList можно перемещать в обоих направлениях; добавление и удаление элементов происходит быстро O(1), а поиск элементов — медленно O(n). Он эффективно реализует LPUSH, RPOP и RPOPLPUSH, но это будет тратить определенное количество времени. для каждого узла необходимо выделить дополнительное пространство памяти. Этот метод кодирования подходит для сцен с большим количеством элементов или крупных элементов.
Структура LinkedList предоставляет головной указатель, хвостовой указатель и длину расчета номера узла для связанного списка. На следующем рисунке показан связанный список, состоящий из структуры списка и трех узлов listNode:
Особенности реализации связанного списка Redis можно резюмировать следующим образом:
Начиная с Redis версии 3.2, базовая структура данных, используемая данными типа списка, представляет собой быстросвязный список. Быстрый список — это двусвязный список со сжатым списком в качестве узла. Двусвязный список разделен на сегменты, и каждый сегмент использует. сжатый список для непрерывного хранения в памяти. Сжатый список представляет собой двустороннюю цепочку, состоящую из указателей «предыдущий» и «следующий».
Учитывая вышеперечисленные недостатки связанных списков, последующие версии Redis преобразовали структуру данных списка и использовали QucikList вместо ZipList и LinkedList. Будучи гибридом ZipList и LinkedList, он разбивает LinkedList на сегменты, каждый сегмент использует ZipList для компактного хранения, а несколько ZipList соединяются последовательно с помощью двунаправленных указателей.
Таким образом, производительность значительно улучшается.
иллюстрировать | |
---|---|
“head” | Представляет головной узел быстросвязного списка. |
“tail” | Представляет хвостовой узел быстросвязного списка. |
“count” | Представляет общее количество элементов во всех узлах быстросвязного списка. |
“len” | Представляет количество узлов в быстросвязном списке. |
“fill” | Максимальный размер узла ziplist. Значение по умолчанию равно 8 КБ. Если размер превышает, будет создан новый Ziplist, соответствующий параметру list-max-ziplist-size, который занимает 16 бит. |
“compress” | Глубина сжатия узла, указывающая, сжимается ли узел с использованием алгоритма LZF, соответствующая параметру list-compress-length, составляющая 1 6 бит. |
Для «заполнения», когда число отрицательное:
Для «заполнения», когда число положительное: максимальное количество элементов, содержащихся в узле ZipList, максимальное значение — 215215.
Для узлов «сжатия» цифры означают следующее:
Используйте команду LPUSH, чтобы добавить новое значение в начало списка:
LPUSH list value [value2 ...]
Вставляет одно или несколько значений в заголовок списка. Если значение ключа не существует, оно будет создано первым, а затем будет выполнена команда LPUSH. Если значение ключа существует, но не относится к типу списка, будет возвращена ошибка.
Используйте команду RPUSH, чтобы добавить новые значения в конец списка:
RPUSH list value [value2 ...]
Вставляет одно или несколько значений в конец списка. Если значение ключа не существует, оно будет создано первым, а затем будет выполнена команда LPUSH. Если значение ключа существует, но не относится к типу списка, будет возвращена ошибка.
Используйте команду LRANGE, чтобы получить значение диапазона в списке:
LRANGE списокимя start end
Получить элементы в указанном диапазоне в списке, 0 означает первый элемент в списке, -1 означает последний элемент в списке.
Используйте команду LPOP, чтобы удалить значение в начале списка и вернуть это значение:
LPOP list
Используйте команду RPOP, чтобы удалить значение в конце списка и вернуть это значение:
RPOP list
Используйте LINDEX для получения значений в списке по индексу:
LINDEX list index
Используйте LREM для удаления указанного значения и количества значений элемента:
LREM list num value
Используйте LLEN, чтобы получить длину списка
llen list
Используйте LTRIM для усечения списка
LTRIM list start end
Используйте RPOPLPUSH для перемещения значений из одного списка в другой
RPOPLPUSH source distination
Удалите последний элемент в исходном списке и добавьте элемент в список назначения, что можно просто понять как «удаление хвоста и вставка заголовка».
Используйте LSET для замены значения в списке
LSET list index value
Вставьте новое значение в список, используя LINSERT в указанной позиции.
LINSERT list BEFORE / AFTER old-value new-value