Redis is an in-memory key value store with benefits that is free and open source. It is implemented in C and it is lightning fast. Redis is mature (version 3.03 right now). It is seriously battle tested and has been used for years by both small and large players. Redis also has an excellent documentation and client libraries for many programming languages.
In this article, I’ll introduce you to the wonders of Redis and explore the basics of how to work with it.
What’s Special About Redis?
Redis is all about speed. The typical approach for making something speedy is to focus on a very narrow slice of functionality and optimize it to death. Redis is different. It provides an abundance of advanced features that match or overtake most key-value stores out there without sacrificing speed. Here is a quick whirlwind of Redis features:
- Rich typed values: strings, dictionaries(hashes), sets, bitmaps and hyperlogs
- Advanced operations of these values
- Optional persistence
- Master-slaves setup
- Asynchronous replication
- Sentinel to monitor, notify and provide automatic fail over
- Publish/Subscribe messaging
- Automatic eviction of least recently used keys
- Automatic eviction of keys with expired TTL (time to live)
- Scripting (with Lua)
Common Use Cases for Redis
Redis is used for a variety of purposes. It really shines as a super-fast distributed cache. But, it is often used as queue (with commands to push and pop items of a list) or as an event router with its publish-subscribe system. Redis is often used to count things with its increment by command. For use cases that involve keeping track of latest items, Redis provides a great alternative to excessive indexing of your relational database. Just keep a trimmed list of items and you’re good to go.
Let’s dive in and play with Redis a little. Download and install Redis here.
If you’re on Mac OSX I recommend using the excellent Homebrew to install it. Ok. You’re back.
Let’s fire up Redis. In a terminal window type: redis-server
You should see something like this:
There is also some sweet ASCII art there. Now, in a separate terminal window or tab type: redis-cli. This is far less dramatic. All you should see is:
~ > redis-cli127.0.0.1:6379>
Anyway, we’re ready to go. Let’s store some keys and values in this key-value store.
Here is how to set and get simple string values:
127.0.0.1:6379> set k vOK127.0.0.1:6379> get k"v"127.0.0.1:6379> get no_such_key(nil)
Bam! You know 80% of Redis. This is pretty much all a simple cache is.
How about deleting keys? No problem.
127.0.0.1:6379> del k(integer) 1127.0.0.1:6379> del no_such_key(integer) 0
Note that Redis tells you how many keys were deleted.
Redis can count for you by ones (incr) or more (incrby):
127.0.0.1:6379> set counter 0OK127.0.0.1:6379> incr counter 1(integer) 1127.0.0.1:6379> incrby counter 3(integer) 4
The “incrby” command stands for increment by. So, you can increment by however many you want. Redis is also nice enough to return the value of the counter after incrementing.
You can countdown too by providing a negative increment:
127.0.0.1:6379> incrby counter -2(integer) 2
Counters are atomic, which is crucial in multi-client environments.
If you want to see what keys are available you can use the “keys” command with pattern matching:
127.0.0.1:6379> set k1 1OK127.0.0.1:6379> set k2 2OK127.0.0.1:6379> keys k*1) "k1"2) "k2"
Redis can store much more than simple string or numbers. Let’s take a look at lists. Lists are ordered collections of items. You can push and pop items from either end. You can query how long a list and you can get slices of the list. Here is a quick demo:
127.0.0.1:6379> lpush superheroes batman(integer) 1127.0.0.1:6379> lpush superheroes spiderman(integer) 2127.0.0.1:6379> llen superheroes(integer) 2127.0.0.1:6379> lrange superheroes 0 -11) "spiderman"2) "batman"
The “lrange” command takes starting index and end index. The -1 means until the end. The first index is 0. Don’t get confused by the display starting with “1”.
Here are some more:
127.0.0.1:6379> rpush superheroes "the incredible hulk" catwoman(integer) 4127.0.0.1:6379> rpop superheroes"catwoman"127.0.0.1:6379> lpop superheroes"spiderman"127.0.0.1:6379> lrange superheroes 0 -11) "batman"2) "the incredible hulk"
This is a pretty complete interface to a data structure that can serve as a random access list (using lrange), a stack (using lpush/lpop), a queue (lpush, rpop) or dequeue (push/pop on both ends).
Sets are often a very good option to model an orderless collection of items. Redis comes through with a complete set of commands to manage sets:
127.0.0.1:6379> sadd primes 2 3 5 7 11 13 17 19(integer) 8127.0.0.1:6379> sadd integers_to_10 1 2 3 4 5 6 7 8 9 10(integer) 10
For example, here we have two sets. One is the primes up to 20 and the other is the integers from 1 to 10.
Now, you can test primality with the “sismember” command:
127.0.0.1:6379> sismember primes 8(integer) 0127.0.0.1:6379> sismember primes 7(integer) 1
To find all primes up to 10 we can use a set operation like intersection:
127.0.0.1:6379> sinter primes integers_to_101) "2"2) "3"3) "5"4) "7"
We got lucky here and the result was sorted, but in general sets are unsorted and we could get the results in any order. Redis supports sorted sets too that have a score associated with each item and it sorts the sets based on the score.
Redis is a very versatile data store with an abundance of advanced features. It also has a relatively new cluster product that extends its capabilities for use cases where a single machine can’t hold the working set. Take the time and study it and incorporate it into your systems. It can be done slowly and the upside could be huge.