The Redis Protocol is pretty great.
It’s not everywhere, but at this point a lot of folks have used Redis. It supports a broad array of data structures like lists, hashes, hyperloglog and even pub/sub. It’s remarkably high throughput, while also being single-threaded so you don’t have any weird concurrency-related behaviors to debug.
My favorite thing about Redis? It’s protocol.
Let’s think about setting a new value using python-redis:
import redis cli = redis.Redis() cli.set('a', 'hello')
The client sends this request over the network:
*3\r\n $3\r\n SET\r\n $1\r\n A\r\n $5\r\n hello\r\n
Every line is terminated by \r\n
. Clients start each command with a line in the format of *3
, which declares the command will have three parameters. Each parameter is two lines, where the first line starts with $
followed by an integer, which declares the number of bytes in the following line, excluding the terminating \r\n
.
The server responds concisely:
+OK\r\n
It worked! +OK\r\n
is the positive confirmation message for all successful operations that don’t have a return value. If it had been an error, for example if we’d tried to call incr
on a string value, it will return an error in format:
-ERR value is not an integer or out of range\r\n
Now, let’s retrieve that value:
# returns 'hello' cli.get('a')
The client sends:
*2\r\n $3\r\n GET\r\n $1\r\n a\r\n
The server responds with:
$5\r\n hello\r\n
There are so many things I love about this protocol!
It’s simple enough that you can implement a simple client or server implementation in an hour or two!
It’s human readable!
The declared line count and line lengths mean you don’t have to parse the contents!
I also think it’s incredible when you line it up against the Memcache protocol, which is an impressive accomplishment in its own right, but much more confusing to implement.
If you wanted to reproduce this experiment yourself, the magic incantation I used was:
sudo ngrep -d lo0 -t '' 'tcp and port 6379'
Which captured all localhost traffic to and from my local Redis server.