What is Redis?

Redis is an in-memory data structure store used to help building high-performance and scalable web applications, similar to Memcached, but with these main differences:
- Redis can persist data to disk, making it a kind of NoSQL database, so data won’t disappear when restarting the server. This feature can be optionally disabled.
- Redis can store more data types besides strings, such as Hashes, Lists, Sets and Sorted Sets. I will talk about them later.
The persistence feature is interesting, but some applications may be affected if there is some power failure and Redis didn’t have time to persist the latest data. For these cases there is another interesting feature: it can append each command to a log. So if a failure occurs, after restarting Redis it can apply all the commands over the data to get back to the latest state.
Redis can be used as a database, cache system, or a message-queue broker. It can also be used in a server group, using primary-secondary asynchronous replication.
Installation
If you’re using macOS, it’s very easy to install Redis using Homebrew:
$ brew install redis
Then you can start it using this command:
$ redis-server /usr/local/etc/redis.conf
The redis.conf
file is where the server is configured.
If you are using Linux, you can use your distribution’s package manager to install it easily.
I will also install the redis-rb
gem to deal with Redis from Ruby:
$ gem install redis
Connecting
Let’s use the Redis CLI utility to connect to the server and check the installation:
$ redis-cli
It should display a prompt with the loopback IP address and the port where the server is running. When entering the ping
command, the server should respond with PONG
:
127.0.0.1:6379> ping
PONG
Yay! The installation is working!
From now on I will switch to the Ruby gem. The commands are the same, but using them as object methods.
Open another terminal tab and fire up irb
. Let’s connect to the server:
require "redis"
=> true
redis = Redis.new
=> #<Redis client v3.2.2 for redis://127.0.0.1:6379/0>
You are connected to the server using the default configuration (localhost and port 6379).
Now ping the server:
redis.ping
=> "PONG"
Strings
Redis can store any value in a string using up to 512 MB.
redis.set 'greeting', 'hello'
=> "OK"
redis.get 'greeting'
=> "hello"
Another interesting way to set a string is by assigning an expiry in seconds:
redis.setex 'temp_greeting', 5, 'hi!'
=> "OK"
redis.get 'temp_greeting'
=> "hi!"
# after waiting for more than 5 seconds
redis.get 'temp_greeting'
=> nil
There are lots of commands for strings. I will show a few below:
# Appending
redis.append 'greeting', '!'
=> 6
redis.get 'greeting'
=> "hello!"# Getting a range
redis.getrange 'greeting', 0, 1
=> "he"# Getting multiple strings:
redis.set 'farewell', 'goodbye'
=> "OK"
redis.mget 'greeting', 'farewell'
=> ["hello", "goodbye"]# Incrementing/decrementing:
redis.set 'counter', 1
=> "OK"
redis.incr 'counter'
=> 2
redis.incrby 'counter', 2
=> 4
redis.decr 'counter'
=> 3
redis.decrby 'counter', 2
=> 1
Hashes
A hash is a collection of key-value pairs that is initialized using a series of strings:
# set a hash with some key-values
redis.hmset 'my_city', 'name', 'Barcelona', 'country', 'Spain'
=> "OK"# add one more key-value
redis.hset 'my_city', 'region', 'Catalonia'
=> true# get the city name
redis.hget 'my_city', 'name'
=> "Barcelona"# get name and region
redis.hmget 'my_city', 'name', 'region'
=> ["Barcelona", "Catalonia"]# get hash contents
redis.hgetall 'my_city'
=> {"name"=>"Barcelona", "country"=>"Spain", "region"=>"Catalonia"}
A few more interesting things we can do with hashes:
# listing keys
redis.hkeys 'my_city'
=> ["name", "country"]# checking existence of keys
redis.hexists 'my_city', 'name'
=> true
redis.hexists 'my_city', 'province'
=> false# setting a value to a non-existing key
redis.hsetnx 'my_city', 'weather', 'sunny'
=> true
redis.hsetnx 'my_city', 'weather', 'rainy'
=> false
redis.hget 'my_city', 'weather'
=> "sunny"
Lists
Lists are a series of strings sorted by insertion order. More can be added on the head or on the tail.
redis.rpush 'brands', 'Apple'
=> 1
redis.rpush 'brands', 'Microsoft'
=> 2
redis.rpush 'brands', ['AMD', 'Nvidia']
=> 4
redis.lrange 'brands', 0, 3
=> ["Apple", "Microsoft", "AMD", "Nvidia"]
redis.lpush 'brands', 'Intel'
=> 5
redis.lrange 'brands', 0, 4
=> ["Intel", "Apple", "Microsoft", "AMD", "Nvidia"]
Values can be extracted from the head or from the tail as well:
redis.lpop 'brands'
=> "Intel"
redis.rpop 'brands'
=> "Nvidia"
Sets
Sets are unordered and non-repeating collection of strings.
# remove the brands list we created before
redis.del 'brands'redis.sadd 'brands', ['Apple', 'Microsoft', 'Intel']
=> 3
redis.smembers 'brands'
=> ["Microsoft", "Apple", "Intel"]# try to add Apple again
redis.sadd 'brands', 'Apple'
=> true
redis.smembers 'brands'
=> ["Microsoft", "Apple", "Intel"]# check if some brands are included
redis.sismember 'brands', 'Samsung'
=> false
redis.sismember 'brands', 'Intel'
=> true
Sorted sets
A sorted set sets a score to each member, from the smallest to the greatest score.
redis.zadd 'colors', 1, 'red'
=> true
redis.zadd 'colors', 2, 'green'
=> true
redis.zadd 'colors', 3, 'blue'
=> true
redis.zrange 'colors', 0, 5, with_scores: true
=> [["red", 1.0], ["green", 2.0], ["blue", 3.0]]# how many members with a score from 0 to 2?
redis.zcount 'colors', 0, 2
=> 2
Conclusion
I have scratched the surface of Redis features, talking about the basic data types and how to use them through the Ruby gem.
There are other interesting features such as messaging, where an instance can create a channel and receive messages from other instances.
Redis is a very useful and efficient piece of software that can be used to enhance our web applications. In fact there are some important gems that use it, like Sidekiq.