Шпаргалка по Redis

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

Я поставил перед собой цель показать возможности Redis с помощью примеров кода. После публикации приму любые предложения по улучшению материала.

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

Ключи


Redis — хранилище данных в формате «ключ-значение». Факты о ключах:
  • Ключи в Redis — бинарно-безопасные (binary safe) строки.
  • Слишком длинные ключи — плохая идея, не только из-за занимаемой памяти, но так же и в связи с увеличением времени поиска определенного ключа в множестве в связи с дорогостоящим сравнением.
  • Хорошая идея — придерживаться схемы при построении ключей: «object-type:id:field».


Типы данных Redis


  • Строки (strings). Базовый тип данных Redis. Строки в Redis бинарно-безопасны, могут использоваться так же как числа, ограничены размером 512 Мб.
  • Списки (lists). Классические списки строк, упорядоченные в порядке вставки, которая возможна как со стороны головы, так и со стороны хвоста списка. Максимальное количество элементов — 232 — 1.
  • Множества (sets). Множества строк в математическом понимании: не упорядочены, поддерживают операции вставки, проверки вхождения элемента, пересечения и разницы множеств. Максимальное количество элементов — 232 — 1.
  • Хеш-таблицы (hashes). Классические хеш-таблицы или ассоциативные массивы. Максимальное количество пар «ключ-значение» — 232 — 1.
  • Упорядоченные множества (sorted sets). Упорядоченное множество отличается от обычного тем, что его элементы упорядочены по особому параметру «score».

Про типы данных Redis есть отдельная хорошая статья: «Структуры данных, используемые в Redis».


Базовые операции


В консоли для общения с Redis используется клиентская программа redis-cli. Рассмотрим базовые операции.

Задача 1, создание, выборка, модификация, удаление и базовая информация об объектах.
Установить и прочитать значения с ключами вида test:1:*. Узнать тип значения, проверить существование элемента, извлечь все поля записи test:1, удалить поле записи test:1.

redis 127.0.0.1:6379> set test:1:string "my binary safe string"
OK                                                             
redis 127.0.0.1:6379> get test:1:string                        
"my binary safe string"
redis 127.0.0.1:6379> getset test:1:string "other value" 
"my binary safe string"                                                                          
redis 127.0.0.1:6379> type test:1:string                       
string                                                         
redis 127.0.0.1:6379> set test:1:vlaue "487"                   
OK                                                             
redis 127.0.0.1:6379> rename test:1:vlaue test:1:value         
OK                                                             
redis 127.0.0.1:6379> exists  test:1:vlaue                     
(integer) 0                                                    
redis 127.0.0.1:6379> exists test:1:value                      
(integer) 1                                                    
redis 127.0.0.1:6379> keys test:1:*                            
1) "test:1:string"                                             
2) "test:1:value"                                              
redis 127.0.0.1:6379> del test:1:value
(integer) 1                        
redis 127.0.0.1:6379> keys test:1:*
1) "test:1:string"                 

Подробности о командах, связанных с этой задачей можно найти в документации в разделах Keys и Strings.

Задача 2, время жизни объекта.

redis 127.0.0.1:6379> ttl test:1:string
(integer) -1
redis 127.0.0.1:6379> expire test:1:string 6000
(integer) 1
redis 127.0.0.1:6379> ttl test:1:string
(integer) 5997

По умолчанию объект не ограничен временем жизни, поэтому TTL возвращает -1, после установки значения командой EXPIRE команда TTL уже возвращает оставшееся количество секунд.

Подробности о командах, связанных с этой задачей можно найти в документации в разделах Keys и Strings.

Задача 3, pipelining, выполнение нескольких команд одним запросом.

PS D:\Programs\Redis\64bit> "set test:1:pvalue 'test'`r`nget test:1:pvalue" | .\redis-cli
OK                                                                                       
"test"                                                                                   

Pipelining удобно использовать для оптимизации массовых вставок.

Задача 4, транзакции.
Для реализации транзакций в Redis используются следующие основные команды:
  • MULTI — начать запись команд для транзакции.
  • EXEC — выполнить записанные команды.
  • DISCARD — удалить все записанные команды.
  • WATCH — команда, обеспечивающая поведение типа «check-and-set» (CAS) — транзакция выполняется только в случае, если другие клиенты не изменили значение переменной. Иначе EXEC не выполнит записанные команды.

redis 127.0.0.1:6379> multi                 
OK                                          
redis 127.0.0.1:6379> set test:1:trValue "1"
QUEUED                                      
redis 127.0.0.1:6379> incr test:1:trValue   
QUEUED                                      
redis 127.0.0.1:6379> decr test:1:trValue   
QUEUED                                      
redis 127.0.0.1:6379> exec                  
1) OK                                       
2) (integer) 2                              
3) (integer) 1                              

Подробности о командах, связанных с этой задачей можно найти в документации в разделе Transactions.

Строки/числа


Задача 5, продемонстрировать основные строковые операции.

redis 127.0.0.1:6379> set test:1:string "hello"            
OK                                                         
redis 127.0.0.1:6379> append test:1:string " world!"       
(integer) 12                                               
redis 127.0.0.1:6379> get test:1:string                    
"hello world!"                                             
redis 127.0.0.1:6379> strlen test:1:string                 
(integer) 12                                               
redis 127.0.0.1:6379> getrange test:1:string 6 10          
"world"                                                    
redis 127.0.0.1:6379> setrange test:1:string 6 "habrahabr!"
(integer) 16                                               
redis 127.0.0.1:6379> get test:1:string                    
"hello habrahabr!"                                         


Задача 6, продемонстрировать операции над числами.

redis 127.0.0.1:6379> set test:1:int 1    
OK                                        
redis 127.0.0.1:6379> incr test:1:int     
(integer) 2                               
redis 127.0.0.1:6379> decr test:1:int     
(integer) 1                               
redis 127.0.0.1:6379> incrby test:1:int 20
(integer) 21                              
redis 127.0.0.1:6379> decrby test:1:int 15
(integer) 6                               

Подробности о командах, связанных с этими задачами можно найти в документации в разделе Strings.

Списки


Задача 7, создать список, продемонстрировать основные операции над списками.

redis 127.0.0.1:6379> rpush test:1:messages "Hello, world!"
(integer) 1                                                
redis 127.0.0.1:6379> rpush test:1:messages "Hello, user!" 
(integer) 2                                                
redis 127.0.0.1:6379> rpush test:1:messages "Wow!"         
(integer) 3                                                
redis 127.0.0.1:6379> lrange test:1:messages 0 2
1) "Hello, world!"                              
2) "Hello, user!"                               
3) "Wow!"               
redis 127.0.0.1:6379> llen test:1:messages     
(integer) 3                                    
redis 127.0.0.1:6379> lpop test:1:messages     
"Hello, world!"                                
redis 127.0.0.1:6379> lpop test:1:messages     
"Hello, user!"                                 
redis 127.0.0.1:6379> lpop test:1:messages     
"Wow!"                                         
redis 127.0.0.1:6379> llen test:1:messages     
(integer) 0                                                            

Подробности о командах, связанных с этой задачей можно найти в документации в разделе Lists.

Множества, упорядоченные множества


Задача 8, создать множество, продемонстрировать основные операции над множествами.

redis 127.0.0.1:6379> sadd test:1:fruits "banana"                                       
(integer) 1                                                                             
redis 127.0.0.1:6379> sadd test:1:fruits "apple"                                        
(integer) 1                                                                             
redis 127.0.0.1:6379> sadd test:1:fruits "strawberry"                                   
(integer) 1                                                                             
redis 127.0.0.1:6379> sadd test:1:yellowThings "banana"                                 
(integer) 1                                                                             
redis 127.0.0.1:6379> sadd test:1:yellowThings "apple"                                  
(integer) 1                                                                             
redis 127.0.0.1:6379> sadd test:1:redThings "strawberry"                                
(integer) 1                                                                             
redis 127.0.0.1:6379> scard test:1:fruits                                               
(integer) 3                                                                             
redis 127.0.0.1:6379> sdiff test:1:fruits test:1:yellowThings                           
1) "strawberry"                                                                         
redis 127.0.0.1:6379> sdiffstore test:1:noYellowFruits test:1:fruits test:1:yellowThings
(integer) 1                                                                             
redis 127.0.0.1:6379> sinter test:1:yellowThings test:1:fruits                          
1) "banana"                                                                             
2) "apple"                                                                              
redis 127.0.0.1:6379> sismember test:1:fruits "banana"                                  
(integer) 1                                                                             
redis 127.0.0.1:6379> sismember test:1:fruits "tomato"                                  
(integer) 0                                                                             
redis 127.0.0.1:6379> smembers test:1:noYellowFruits                                    
1) "strawberry"                                                                         
redis 127.0.0.1:6379> smove test:1:yellowThings test:1:redThings "apple"                
(integer) 1                                                                             
redis 127.0.0.1:6379> smembers test:1:redThings                                         
1) "strawberry"                                                                         
2) "apple"                                                                              
redis 127.0.0.1:6379> spop test:1:redThings                                             
"apple"                                                                                 
redis 127.0.0.1:6379> srandmember test:1:fruits                                         
"apple"                                                                                 
redis 127.0.0.1:6379> srem test:1:fruits "banana"                                       
(integer) 1                                                                             
redis 127.0.0.1:6379> sunion test:1:yellowThings test:1:redThings                       
1) "strawberry"                                                                         
2) "banana"                                                                             
redis 127.0.0.1:6379> sunionstore test:1:allThings test:1:yellowThings test:1:redThings 
(integer) 2                                                                             
redis 127.0.0.1:6379> smembers test:1:allThings                                         
1) "strawberry"                                                                         
2) "banana"                                                                             

Подробности о командах, связанных с этой задачей можно найти в документации в разделе Sets.

Задача 9, создать упорядоченное множество и продемонстрировано основные операции над ним.
В упорядоченном множестве элементы сравниваются по дополнительному параметру «score».

redis 127.0.0.1:6379> zadd hackers 1953 "Richard Stallman"  
(integer) 1                                                 
redis 127.0.0.1:6379> zadd hackers 1940 "Alan Kay"          
(integer) 1                                                 
redis 127.0.0.1:6379> zadd hackers 1965 "Yukihiro Matsumoto"
(integer) 1                                                 
redis 127.0.0.1:6379> zadd hackers 1916 "Claude Shannon"    
(integer) 1                                                 
redis 127.0.0.1:6379> zadd hackers 1969 "Linus Torvalds"    
(integer) 1                                                 
redis 127.0.0.1:6379> zadd hackers 1912 "Alan Turing"       
(integer) 1                                                 
redis 127.0.0.1:6379> zrange hackers 0 -1                   
1) "Alan Turing"                                            
2) "Claude Shannon"                                         
3) "Alan Kay"                                               
4) "Richard Stallman"                                       
5) "Yukihiro Matsumoto"                                     
6) "Linus Torvalds"                                         
redis 127.0.0.1:6379> zrevrange hackers 0 -1                
1) "Linus Torvalds"                                         
2) "Yukihiro Matsumoto"                                     
3) "Richard Stallman"                                       
4) "Alan Kay"                                               
5) "Claude Shannon"                                         
6) "Alan Turing"                                            
redis 127.0.0.1:6379> zrangebyscore hackers -inf 1950       
1) "Alan Turing"                                            
2) "Claude Shannon"                                         
3) "Alan Kay"                                               
redis 127.0.0.1:6379> zremrangebyscore hackers 1940 1960    
(integer) 2                                                 
redis 127.0.0.1:6379> zrange hackers 0 -1                   
1) "Alan Turing"                                            
2) "Claude Shannon"                                         
3) "Yukihiro Matsumoto"                                     
4) "Linus Torvalds"                                         

Подробности о командах, связанных с этой задачей можно найти в документации в разделе Sorted sets.

Хеш-таблицы


Задача 10, Создать хеш-таблицу и продемонстрировать основные операции над хешами.

redis 127.0.0.1:6379> hset users:1 name "Andrew"             
(integer) 1                                                  
redis 127.0.0.1:6379> hset users:1 email "[email protected]"
(integer) 1                                                  
redis 127.0.0.1:6379> hkeys users:1                          
1) "name"                                                    
2) "email"                                                   
redis 127.0.0.1:6379> hvals users:1                          
1) "Andrew"                                                  
2) "[email protected]"                                      
redis 127.0.0.1:6379> hgetall users:1                        
1) "name"                                                    
2) "Andrew"                                                  
3) "email"                                                   
4) "[email protected]"                                      
redis 127.0.0.1:6379> hset users:1 test 1                    
(integer) 1                                                  
redis 127.0.0.1:6379> hincrby users:1 test 123               
(integer) 124                                                
redis 127.0.0.1:6379> hvals users:1                          
1) "Andrew"                                                  
2) "[email protected]"                                      
3) "124"                                                     
redis 127.0.0.1:6379> hdel users:1 test                      
(integer) 1                                                  
redis 127.0.0.1:6379> hvals users:1                          
1) "Andrew"                                                  
2) "[email protected]"                                      

Подробности о командах, связанных с этой задачей можно найти в документации в разделе Hashes.

Pub/Sub, сообщения в Redis


Задача 11, подписаться на сообщения на одном клиенте и отправить сообщение из другого.
Приведем окна двух клиентов, в первом окне совершается подписка на сообщения и видно отправленное из второго окна сообщение.

redis 127.0.0.1:6379> SUBSCRIBE messages  
Reading messages... (press Ctrl-C to quit)
1) "subscribe"                            
2) "messages"                             
3) (integer) 1                            
1) "message"                              
2) "messages"                             
3) "Hello world!"                         

redis 127.0.0.1:6379> PUBLISH messages "Hello world!"
(integer) 1                                          


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

redis 127.0.0.1:6379> PSUBSCRIBE news.*   
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"                           
2) "news.*"                               
3) (integer) 1                            
1) "pmessage"                             
2) "news.*"                               
3) "news.art"                             
4) "New picture!"                         
1) "pmessage"                             
2) "news.*"                               
3) "news.cinema"                          
4) "New movie!"                           

redis 127.0.0.1:6379> PUBLISH news.art "New picture!" 
(integer) 1                                           
redis 127.0.0.1:6379> PUBLISH news.cinema "New movie!"
(integer) 1                                           

Подробности о командах, связанных с этими задачами можно найти в документации в разделе Pub/Sub.

Комментарии 15

    +1
    Как-то мало тут практических советов. Можно сказать вообще нет. Почти все надергано из доки.
      +2
      Задача 3, pipelining, выполнение нескольких команд одним запросом.

      Так удобнее и нагляднее:
      $ redis-cli set test:1:pvalue 'test'
      OK
      

      Кстати, параметр -n позволяет указать номер используемой базы (коих по умолчанию 16).

      Так же из практики использования добавил бы еще удаление ключей по заданной маске. Конечно команда DEL не поддерживает работу с масками, но вопрос решаем через конвеер, xargs и KEY:
      $ redis-cli -n 3 KEYS 'test*' | xargs redis-cli -n 3 DEL
      (integer) 1
      
        +1
        KEYS — моветон, в redis 2.8 появилась альтернатива в виде сканеров.
          +1
          А у всех уже поголовно обновились до 2.8? ;)
          Новая версия вышла не так давно что бы среднестатистический пользователь начал её использовать.
        +1
        Исправьте:
        после установки значения командой EXPIRES
          0
          Исправил, спасибо
          +2
          Слишком длинные ключи — плохая идея

          А какова всё-таки максимальная длина ключа?
          Здесь antirez сообщает о
          up to 2^31 bytes
          , но в официальной документации подтверждения я не смог обнаружить.
            0
            Вопрос интересный. Но я тоже не нашел информации в документации по этому поводу.
            +3
            Это самая бесполезная статья по Redis, которую я видел. Все более лаконично и понятно есть на сайте в двух кликах от вас.
              0
              Да уж, зашел посмотреть на шпаргалку, а тут какие-то задачки. Шпаргалка — это то, что распечатать и на стенку повесить можно.
                +1
                Знание развивается, когда опыт перенимается и вносятся улучшения. Вместите всю эту информацию в один лист в понятной форме, и я буду первым, кто распечатает.
              +3
              У меня небольшой вопрос к опытным пользователям Redis. Длина названия ключа сильно влияет на размер базы?

              Поясню. Скажем есть тип данных хэш для пользователя с несколькими полями: login, password, sex и т.д.
              Тогда для наглядности вот один из способов получить данные

              hmget user:100, login, password, sex

              На сколько база будет меньше, если назвать соответствующие поля, скажем, l, p, s?

              hmget user:100, l, p, s

              То есть для каждой записи в базе сохраняется название поля или нет? Стоит оптимизировать названия полей в базе или нет?

                +2
                То есть для каждой записи в базе сохраняется название поля или нет?
                Конечно, ведь в разных записях могут быть разные поля.

                Стоит оптимизировать названия полей в базе или нет?
                Моё мнение — стоит в пределах разумного, особенно если много записей. Это, безусловно, сэкономит в первую очередь память.

                Всё вышеперечисленное справедливо также и для других schema-less БД (например, MongoDB)
                  +1
                  Сделайте в своей клиентской библиотеке модель с приватными ключами и публичными методами. Где приватные ключи будут иметь короткие имена, а методы — человекочитаемые.

                  Плюс не забывайте записывать схему редиса при любом изменении.

                  Названия ключей и полей, по возможности, стоит делать короче, как и стараться меньше использовать ZSET, где SCORE тоже достаточно прожорливое поле.

                  PS И не стоит сильно заморачиваться с длиной если данных не много и их рост не планируется.
                  0
                  Текущий мануал написан для redis-cli. Но в клиентах могут быть отличия в реализации некоторых комманд и особенно в том, что они возвращают. Можно было бы об этом написать.

                  Так же мне бы было интересно почитать практические советы о работе с редис на большом трафике. Есть много вопросов, которые можно было бы обсудить. Например, о настройки конфига под конкретные задачи.

                  Так же можно было бы написать о встроенном языке lua для редис. У него есть свои ограничения по сравнению с обычной версией луа.

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

                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                  Самое читаемое