2015-12-27
An introduction to Redis.
I’ve recently rekindled my love for Redis through work, and thought it would be an acceptable topic for my first technical blog post. I’m currently using Redis for the Form.io analytics system, and previously for a queueing system, but its elegance lures me for every project.
Redis is an in-memory data store with a multitude of uses. It is blazing fast and used by everyone
from Coinbase to Kickstarter to Alibaba, for more see: techstacks.io. The general
topic of Redis is quite large, so in the first part of this series, I am going to generally cover: Keys
, Strings
,
Lists
, and Transactions
. Feel free to follow along in your terminal and get your feet wet with Redis!
It should be noted that the Redis Documentation is terrific, and even shows asymptotic
time complexity (in big O) for each command, so you can judge whether or not a command is acceptable to use in your
application.
Note: All redis commands can be used in lowercase, but I'll stay consistent with the documentation and use uppercase
for all the examples in this series.
You can download the latest version of Redis here, and follow the installation directions.
When complete, start the redis-server
in the background and then connect with the redis-cli
.
$ redis-server
-- output condensed --
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 3.0.4 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in standalone mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 6379
| `-._ `._ / _.-' | PID: 75162
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | http://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'
-- output condensed --
$ redis-cli
127.0.0.1:6379>
Redis is a key value store, it can be visualized as a JSON object:
{
"hello": "world"
}
You can easily create, read, type check, and delete keys with SET
, GET
, TYPE
and DEL
commands respectively.
$ redis-cli
127.0.0.1:6379> SET hello world
OK
127.0.0.1:6379> GET hello
"world"
127.0.0.1:6379> TYPE hello
string
127.0.0.1:6379> DEL hello
(integer) 1
127.0.0.1:6379> GET hello
(nil)
127.0.0.1:6379>
Additionally, there are two forms of updates, one for the key and the other for the value: RENAME
and SET
127.0.0.1:6379> SET hello world
OK
127.0.0.1:6379> RENAME hello foo
OK
127.0.0.1:6379> GET foo
"world"
127.0.0.1:6379> SET foo bar
OK
127.0.0.1:6379> GET foo
"bar"
127.0.0.1:6379>
Redis also supports key expiration, but by default, keys don’t have an expiration time. You can see if a key exists, and
when it expires with EXISTS
and TTL
, or add/remove an expiration time with EXPIRE
and PERSIST
.
NOTE: Times are given in seconds, but there are commands for milliseconds.
127.0.0.1:6379> SET hello world
OK
127.0.0.1:6379> EXISTS hello
(integer) 1
127.0.0.1:6379> EXPIRE hello 60
(integer) 1
127.0.0.1:6379> TTL hello
(integer) 56
127.0.0.1:6379> PERSIST hello
(integer) 1
127.0.0.1:6379> TTL hello
(integer) -1
127.0.0.1:6379>
Lists are another commonly used storage type, which can be visualized as a JSON Array:
{
"hello": [
"world1",
"world2",
"world3"
]
}
A list can have items added, removed, trimmed, and retrieved with LPUSH
, LPOP
, LTRIM
, and LRANGE
.
NOTE: Most of the list commands take a start and end index, where 0 is the first element and -1 is the last.
127.0.0.1:6379> LPUSH hello world1
(integer) 1
127.0.0.1:6379> LPUSH hello world2
(integer) 2
127.0.0.1:6379> LPUSH hello world3
(integer) 3
127.0.0.1:6379> LRANGE hello 0 -1
1) "world3"
2) "world2"
3) "world1"
127.0.0.1:6379> LTRIM hello 0 1
OK
127.0.0.1:6379> LRANGE hello 0 -1
1) "world3"
2) "world2"
127.0.0.1:6379> LPOP hello
"world3"
127.0.0.1:6379> LRANGE hello 0 -1
1) "world2"
127.0.0.1:6379>
Notice how the previous operations are prepended with an L. Most of the list functions come in multiple variations that
follow the given naming pattern:
B* -> Blocking
L* -> Starting from the Left
R* -> Starting from the Right
*X -> If it exists
Transactions in Redis are not traditional transactions, in the sense that they can’t be rolled back. However, transactions are collection of commands which can be executed conditionally and save a tremendous amount of time by using a single network request for all of the queries together.
A Transaction can be initialized, canceled, and executed with MULTI
, DISCARD
and EXEC
. When a transaction is
started, none of the commands will be executed until the transaction block is finished with an EXEC
call, and each
command is executed atomically in order.
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> GET hello
QUEUED
127.0.0.1:6379> EXEC
1) (nil)
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> GET hello
QUEUED
127.0.0.1:6379> DISCARD
OK
127.0.0.1:6379>
You may have considered that the previous example could cause issues in a multi threaded environment (Redis itself is
single threaded so all operations are atomic and executed in order). In the situation where a transaction is dependent
on a previous transaction or query, the WATCH
command can be used to conditionally execute a transaction. If a watched
key is changed by another source, the transaction will not execute. Additionally all the watched keys can be removed
with the UNWATCH
command.
127.0.0.1:6379> WATCH hello
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET hello world
QUEUED
127.0.0.1:6379> get hello
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) "world"
127.0.0.1:6379> UNWATCH
OK
As stated earlier, the aim of this post was to scratch the surface of Redis. Many things are possible with Redis, and I plan on making a practical demo for how it can be integrated into a project rather than interactive terminal use. That being said, I also want to explore the depths of Redis, so perhaps there are a few follow up posts including clusters and scripting. I urge everyone to try Redis themselves and actually feel how fast it is compared to other databases. The official documentation is on the Redis Website, where you can find more commands than I previewed here.
I hope someone found this post helpful, and as always feel free to reach out to me on
Twitter and suggest new topics for me to cover!
− Zack
EDIT: My Intro to Redis part 2 is now up!