Redis — это популярная нереляционная база данных, реализующая хранилище типа «Ключ — Значение». Данная статья посвящена основным типам данных и операциям и является вступительной к серии статей о Redis, в рамках которой будет рассматриваться и работа с Redis при помощи Spring Data.
Что такое Redis
Redis — это хранилище данных типа «Ключ — Значение» (аналог Map в Java, Kotlin и других языках программирования). В отличие от более традиционных реляционных баз данных вроде MySQL и PostgreSQL или нереляционных вроде MongoDB и Cassandra, в Redis отсутствуют таблицы и коллекции, а вся база данных представляет собой справочник, состоящий из ключей и значений. По умолчанию Redis может хранить до 4 294 967 295 (2^32-1) пар «ключ — значение».
При этом Redis является высокопроизводительной базой данных: заявляется о производительности в 100 000 GET/SET-команд в секунду на сервере начального уровня под управлением GNU/Linux, что делает Redis весьма мощным инструментом для ряда задач, вроде кеширования, индексации, организации поиска и аналитики. Обеспечивается такая производительность, в том числе, за счёт хранения данных в оперативной памяти.
Основные типы данных
Redis OSS поддерживает следующие типы данных для значений: строки, хеш-таблицы, списки, множества, потоки, битовые карты и поля, а так же геопространственные структуры. Кроме этого Redis Stack и Redis Enterprise поддерживают JSON, вероятностные структуры данных и временные ряды. Предлагаю вкратце разобраться с основными типами данных.
Строки (String)
Строки являются основным типом данных в Redis для значений, а для ключей — и вовсе единственным. С точки зрения разработчиков программного обеспечения на языках программирования вроде Java, Kotin и других, Redis в целом можно представить себе как Map<String, String>
.
По умолчанию максимальный размер строкового значения составляет 512Мб.
Основные операции
set <key> <value>
— устанавливает значение для указанного ключа
1 2 3 |
# Присваивание значения bar ключу foo 127.0.0.1:6379> set foo bar OK |
get <key>
— возвращает текущее значение или nil
1 2 3 4 5 6 7 |
# Получение несуществующего значения 127.0.0.1:6379> get baz (nil) # Получение существующего значения 127.0.0.1:6379> get foo "bar" |
del <key>
— удаляет значение, применима ко всем ключам, вне зависимости от типа значения
1 2 3 |
# Удаление значения 127.0.0.1:6379> del foo (integer) 1 |
Строки в Redis могут себя вести как числа, битовые карты и поля, более подробно это и остальные операции будут рассмотрены в одной из следующих статей.
Хеш-таблицы (Hash table)
Хеш-таблицы представляют собой структуру типа «ключ — значение». Redis позволяет хранить до 4 294 967 295 (2^32-1) пар «ключ — значение» в хеш-таблице.
Аналог хеш-таблиц в Java — HashMap.
Основные операции
hset <key> <hashkey> <hashvalue>
— установка значения в хеш-таблице, при этом пары hashkey-hashvalue могут повторяться. Если значение присваивается существующей хеш-таблице, то существующие значения будут заменены новыми.
1 2 3 4 5 6 7 8 9 10 11 |
# Пример установки ключа manufacturer в хеш-таблице car 127.0.0.1:6379> hset car manufacturer Chevrolet (integer) 1 # Пример установки новых значений для ключей model и year 127.0.0.1:6379> hset car manufacturer Chevrolet model Tahoe year 2024 (integer) 2 # Количество добавленных ключей (model и year) # Пример замены значений для ключей manufacturer и model 127.0.0.1:6379> hset car manufacturer Ford model Expedition year 2024 (integer) 0 |
hget <key> <hashkey>
— получение значения из хеш-таблицы
1 2 |
127.0.0.1:6379> hget car manufacturer "Ford" |
hmget <key> <hashkey1> <hashkey2>
— получение значений для одного и более ключей из хеш-таблицы
1 2 3 |
127.0.0.1:6379> hmget car manufacturer year "Ford" "2024" |
hgetall <key>
— получение всех ключей и значений указанной хеш-таблицы
1 2 3 4 5 6 7 |
127.0.0.1:6379> hgetall car 1) "manufacturer" 2) "Ford" 3) "model" 4) "Expedition" 5) "year" 6) "2024" |
hdel <key> <hashkey1> <hashkey2>
— удаление указанных ключей из хеш-таблицы
1 2 |
127.0.0.1:6379> hdel car year (integer) 1 |
Списки (List)
Списки представляют собой упорядоченные последовательности элементов и во многих языках программирования реализованы с использованием массивов (например, ArrayList в Java), но в Redis списки являются именно связанными списками, благодаря чему при помощи их можно реализовывать, например, логику очередей. Списки в Redis могут содержать дублирующиеся элементы.
Аналог списков Redis в Java — LinkedList.
Основные операции
lpush <key> <element1> <element2> <elementn>
(left push) — добавление элементов в начало (левый край) спискаrpush <key> <element1> <element2> <elementn>
(right push) — добавление элементов в конец (правый край) списка
При вставке нескольких элементов в начало списка стоит помнить, что элементы вставляются в список поочерёдно, а не вместе. Если вызвать операцию lpush list element1 element2
, то фактический порядок элементов в списке будет element2 element1
, так как сначала в начало списка будет добавлен element1
, а затем в начало же списка будет добавлен element2
. При вызове операции rpush
порядок вставляемых элементов не изменяется.
1 2 3 4 5 |
127.0.0.1:6379> lpush manufacturers Ford Chevrolet # добавление двух элементов в начало списка (integer) 2 # количество элементов в списке 127.0.0.1:6379> rpush manufacturers GMC # добавление элемента в конец списка (integer) 3 # количество элементов в списке |
llen <key>
(list length) — получение количества элементов списка
1 2 |
127.0.0.1:6379> llen manufacturers # получение количества элементов (integer) 3 # количество элементов в списке |
lrange <key> <start> <stop>
(list range) — получение элементов списка без их удаления. При помощи start и stop можно выбирать диапазон получаемых значений, первый элемент имеет позицию 0, диапазон указывается включительно. В качестве верхней границы можно указывать число, превышающее реальное количество элементов в списке или -1, в этом случае будут возвращены все элементы списка.
1 2 3 4 5 6 7 8 9 10 11 |
127.0.0.1:6379> lrange manufacturers 0 -1 # получение всех элементов 1) "Chevrolet" 2) "Ford" 3) "GMC" 127.0.0.1:6379> lrange manufacturers 0 1 # получение элементов 0 и 1 1) "Chevrolet" 2) "Ford" 127.0.0.1:6379> lrange manufacturers 1 1 # получение элемента 1 1) "Ford" |
lpop <key> <count>
(left pop) — извлечение элементов из начала списка. Возвращает и удаляет указанное количество элемент из начала списка (по умолчанию 1).rpop
(right pop) — извлечение элемента из конца списка. Возвращает и удаляет указанное количество элемент из начала списка (по умолчанию 1). При извлечении двух и более элементов из конца списка элементы будут возвращены в обратном порядке, так как извлекаться будут по очереди из конца списка.
1 2 3 4 5 6 7 8 9 |
127.0.0.1:6379> lpop manufacturers # извлечение элемента из начала списка "Chevrolet" 127.0.0.1:6379> rpop manufacturers 2 # извлечение 2-х элементов из конца списка 1) "GMC" 2) "Ford" 127.0.0.1:6379> rpop manufacturers # извлечение элемента из конца пустого списка (nil) |
blpop <key> <timeout>
(blocking left pop) — блокирующее извлечение элемента из начала списка. Возвращает и удаляет элемент из начала списка. Если список пуст, то дожидается появления первого элемента указанное количество секунд.
1 2 3 4 5 6 7 8 9 10 |
# блокирующее извлечение элемента из начала списка с таймаутом в 3 секунды 127.0.0.1:6379> blpop manufacturers 3 (nil) # элемент не появился (3.06s) # затраченное время # блокирующее извлечение элемента из начала списка с таймаутом в 5 секунд 127.0.0.1:6379> blpop manufacturers 5 1) "manufacturers" 2) "Chevrolet" # элемент появился (2.56s) # затраченное время |
ltrim <key> <start> <stop>
(list trim) — усечение списка до указанного диапазона, диапазон задаётся от 0, границы указываются включительно
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# Добавляем в список 5 элемента 127.0.0.1:6379> lpush manufacturers Ford Chevrolet GMC Jeep Dodge (integer) 5 # Список 127.0.0.1:6379> lrange manufacturers 0 -1 1) "Dodge" 2) "Jeep" 3) "GMC" 4) "Chevrolet" 5) "Ford" # Усекаем список до элементов 2-4 127.0.0.1:6379> ltrim manufacturers 2 4 OK # Полученный список 127.0.0.1:6379> lrange manufacturers 0 -1 1) "GMC" 2) "Chevrolet" 3) "Ford" |
lmove <source> <destination> <left|right> <left|right>
(list move) — атомарное перемещение элемента из одного списка в другой.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# Добавляем в список 5 элемента 127.0.0.1:6379> lpush manufacturers Ford Chevrolet GMC Jeep Dodge (integer) 5 # Список 127.0.0.1:6379> lrange manufacturers 0 -1 1) "Dodge" 2) "Jeep" 3) "GMC" 4) "Chevrolet" 5) "Ford" # Переместим первый элемент manufacturers в конец списка usmanufacturers 127.0.0.1:6379> lmove manufacturers usmanufacturers left right "Dodge" # перемещённый элемент # Состояние списков 127.0.0.1:6379> lrange manufacturers 0 -1 1) "Jeep" 2) "GMC" 3) "Chevrolet" 4) "Ford" 127.0.0.1:6379> lrange usmanufacturers 0 -1 1) "Dodge" # Переместим последний элемент manufacturers в начало списка usmanufacturers 127.0.0.1:6379> lmove manufacturers usmanufacturers right left "Ford" # перемещённый элемент # Состояние списков 127.0.0.1:6379> lrange manufacturers 0 -1 1) "Jeep" 2) "GMC" 3) "Chevrolet" 127.0.0.1:6379> lrange usmanufacturers 0 -1 1) "Ford" 2) "Dodge" |
blmove <source> <destination> <left|right> <left|right> <timeout>
(blocking list_move) — атомарное блокирующее перемещение элемента из одного списка в другой. Поведение аналогичноlmove
, но появляется таймаут ожидания, если исходный список пустой.
1 2 3 4 5 6 7 8 |
# Переместим первый элемент manufacturers в конец списка usmanufacturers с таймаутом 5 секунд 127.0.0.1:6379> blmove manufacturers usmanufacturers left right 5 "Dodge" # перемещённый элемент # Попытаемся переместить элемент из пустого списка 127.0.0.1:6379> blmove manufacturers usmanufacturers right left 5 (nil) # перемещаемый элемент отсутствует (5.06s) # затраченное время |
Множества (Set)
Множество (set) представляют собой неупорядоченный набор уникальных элементов.
Аналог множества Redis в Java — HashSet.
Основные операции
sadd <key> <element1> <element2> <elementN>
(set add) — добавление элементов в множество
1 2 3 |
# Добавление 5 элементов в множество manufacturers 127.0.0.1:6379> sadd manufacturers Ford Chevrolet Dodge Jeep GMC (integer) 5 # количество добавленных элементов |
scard <key>
(set cardinality) — получение количества элементов множества
1 2 |
127.0.0.1:6379> scard manufacturers (integer) 6 |
smembers <key>
(set members) — вывод элементов множества
1 2 3 4 5 6 |
127.0.0.1:6379> smembers manufacturers 1) "Ford" 2) "Chevrolet" 3) "Dodge" 4) "Jeep" 5) "GMC" |
srem <key> <element1> <element2> <elementN>
(set remove) — удаление элементов из множества
1 2 3 4 5 6 7 8 9 |
# Удаление элементов Jeep и Ford из множества 127.0.0.1:6379> srem manufacturers Jeep Ford (integer) 2 # количество удалённых элементов # Итоговое множество 127.0.0.1:6379> smembers manufacturers 1) "Chevrolet" 2) "Dodge" 3) "GMC" |
sismember <key> <value>
(set is member) — проверка, является ли значение элементом указанного множества
1 2 3 4 5 6 7 |
# Проверка, является ли Chevrolet элементом множества manufacturers 127.0.0.1:6379> sismember manufacturers Chevrolet (integer) 1 # да # Проверка, является ли Ford элементом множества manufacturers 127.0.0.1:6379> sismember manufacturers Ford (integer) 0 # нет |
sinter <key1> <key2> <keyN>
(set intersection) — получение элементов, которые встречаются во всех указанных множествах
1 2 3 4 5 6 7 8 9 10 11 12 13 |
# Добавление 6 элементов в множество manufacturers 127.0.0.1:6379> sadd manufacturers Ford Chevrolet GMC BMW Toyota Audi (integer) 6 # Добавление 3 элементов в множество usmanufacturers 127.0.0.1:6379> sadd usmanufacturers Ford Chevrolet GMC (integer) 3 # Поиск общих элементов 127.0.0.1:6379> sinter manufacturers usmanufacturers 1) "Ford" 2) "Chevrolet" 3) "GMC" |
Сортированные множества (Sorted Set)
Сортированные множества представляют собой наборы уникальных элементов, отсортированных по весу (score). Если несколько элементов имеют одинаковый вес, то они сортируются по алфавиту.
В некоторой мере аналогом сортированных множеств в Java является SortedSet и его реализации.
Основные операции
zadd <key> <nx|xx> <gt|lt> <ch> <incr> <score> <member>
— добавление элемента в сортированное множество. Аргументы операции:nx
— только добавлять новые элементы, не изменяя существующиеxx
— только изменять существующие элементы, не добавляя новыеgt
— обновлять элементы только, если новый вес больше существующегоlt
— обновлять элементы только, если новый вес меньше существующегоch
— показывать количество изменённых элементов, а не добавленныхincr
— увеличивать существующий вес на указанный (может быть использован только с одной парой вес-элемент)score
— вес элементаmember
— элемент
Команда zadd
может принимать несколько пар вес-элемент (score member), если не используется аргумент incr
. Аргументы nx
, gt
и lt
являются взаимоисключающими.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# Добавление в множество трёх элементов 127.0.0.1:6379> zadd manufacturers 10 Chevrolet 20 GMC 30 Ford (integer) 3 # Содержимое множества 127.0.0.1:6379> zrange manufacturers 0 -1 withscores 1) "Chevrolet" 2) "10" 3) "GMC" 4) "20" 5) "Ford" 6) "30" # Изменение весов элементов 127.0.0.1:6379> zadd manufacturers 30 Chevrolet 10 GMC 20 Ford (integer) 0 # количество добавленных элементов, было бы 3 при исопльзовании аргумента ch # Содержимое множества 127.0.0.1:6379> zrange manufacturers 0 -1 withscores 1) "GMC" 2) "10" 3) "Ford" 4) "20" 5) "Chevrolet" 6) "30" # Увеличение веса элемента Ford на 20 127.0.0.1:6379> zadd manufacturers incr 20 Ford "40" # Итоговый вес # Содержимое множества 127.0.0.1:6379> zrange manufacturers 0 -1 withscores 1) "GMC" 2) "10" 3) "Chevrolet" 4) "30" 5) "Ford" 6) "40" |
zcard <key>
— получение количества элементов множества
1 2 |
127.0.0.1:6379> zcard manufacturers (integer) 3 # количество элементов |
zcount <key> <score-min> <score-max>
— получение количества элементов множества в указанном диапазоне весов. Границы диапазона указываются включительно.
1 2 |
127.0.0.1:6379> zcount manufacturers 10 30 (integer) 2 # количество элементов |
zrange <key> <start> <stop> <byscore | bylex> <rev> <limit offset count> <withscores>
— получение элементов множества. Аргументы операции:start
иstop
— диапазон элементов множества, числа если используется сортировка по весу, иначе элементы списка с ведущей[
или(
для указания включения или исключения элемента в диапазоне, либо- +
— для использования всего диапазона.byscore | bylex
— сортировка по весу или алфавитному порядкуrev
— получение элементов в обратном порядкеlimit offset count
— дополнительное ограничение получаемого подмножестваwithscores
— возврат элементов с весами (если не указан аргументbylex
)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# Вывод элементов множества с сортировкой по весу 127.0.0.1:6379> zrange manufacturers 0 -1 1) "GMC" 2) "Chevrolet" 3) "Ford" # Вывод элементов множества и их веса с сортировкой по весу 127.0.0.1:6379> zrange manufacturers 0 -1 withscores 1) "GMC" 2) "10" 3) "Chevrolet" 4) "30" 5) "Ford" 6) "40" # Вывод элементов множества до GMC (исключительно) с сортировкой по алфавиту 127.0.0.1:6379> zrange manufacturers - ("GMC" bylex 1) "Chevrolet" 2) "Ford" # Вывод элементов множества после Ford (включительно) с сортировкой по алфавиту 127.0.0.1:6379> zrange manufacturers ["Ford" + bylex 1) "Ford" 2) "GMC" # Вывод всех элементов множества с сортировкой по алфавиту 127.0.0.1:6379> zrange manufacturers - + bylex 1) "Chevrolet" 2) "Ford" 3) "GMC" |
zrank <key> <member> <withscore>
— получение позиции элемента во множестве
1 2 3 4 5 6 |
127.0.0.1:6379> zrank manufacturers GMC (integer) 0 127.0.0.1:6379> zrank manufacturers GMC withscore 1) (integer) 0 2) "10" |
Итого
В данной статье я вкратце рассказал о том, что такое Redis, описал наиболее используемые типы данных и основным операции с ними. В будущих статьях каждый тип данных будет рассмотрен более подробно, а так же будет описана работа с Redis в проектах на Java.