As we described in the previous recipe, Redis is merely a non-blocking, I/O multiplexing TCP server that accepts and processes requests from clients. In other words, in spite of the complexity within the Redis Server, you can talk to Redis over the TCP connection in various languages. The term protocol stands for the language used between a server and a client in the networking communication. As for Redis, REdis Serialization Protocol (RESP) is the protocol. In this recipe, we'll see how the RESP works in Redis.
One thing should be noted: Even at first glance, it's a little bit advanced for a beginner to go through this recipe. However, we do believe that learning the RESP, as basic knowledge, is not that difficult and it will be of benefit to you, in that understanding the various kinds of clients and proxies implemented in different programming languages will no longer be a mystery to you.
Of course, you can skip this recipe if you like and it won't bother you too much when reading the following chapters.
You need an up-and-running Redis Server, as we described in the Starting and shutting down Redis recipe in this chapter.
The tool, netcat (nc
) should be installed. In this recipe, we have the nc
command in Ubuntu 16.04.3 LTS for netcat. You can use Cygwin to install netcat if you work under Windows.
To understand the Redis protocol, take the following steps:
- Send the
PING
command to the Redis Server with netcat:
Instead of sending the command PING
in redis-cli
, let's build the command using RESP:
$ echo -e "*1\r\n\$4\r\nPING\r\n" | nc 127.0.0.1 6379 +PONG
- Use the
SET
andINCR
commands to set an integer and increase it by one:
$ echo -e "*3\r\n\$3\r\nset\r\n\$5\r\nmykey\r\n\$1\r\n1\r\n" | nc 127.0.0.1 6379 +OK $ echo -e "*2\r\n\$4\r\nINCR\r\n\$5\r\nmykey\r\n" | nc 127.0.0.1 6379 :2
You may encounter the following error when you send a non-existent command:
$ echo -e "*2\r\n\$3\r\ngot\r\n\$3\r\nfoo\r\n" | nc 127.0.0.1 6379 -ERR unknown command 'got'
Multi-commands can be combined and sent to the Redis Server in a single network transmission:
$ echo -e "*3\r\n\$3\r\nset\r\n\$3\r\nfoo\r\n\$3\r\nbar\r\n*2\r\n\$3\r\nget\r\n\$3\r\nfoo\r\n" | nc 127.0.0.1 6379 +OK $3 bar
There is a big chance that you will go through these commands in tremendous confusion. As we stated in the Getting ready section in this recipe, these commands are the language in which the Redis Server and client talk to each other. It's easy for you to learn them in that there are only five types in RESP.
Let's take a look at each command.
First, we sent *1\r\n\$4\r\nPING\r\n
to the Redis Server. The command begins with an asterisk indicating this is an arrays type.
Look at the following:
1
stands for the size of this array.\r\n
(CRLF) is the terminator of each part in RESP.- The backslash before
$4
is the escape character for the$
sign.$4
tells you that the following is a bulk string type of four characters long. PING
is the string itself.+PONG
is the string thePING
command returned. The plus sign tells you that it's a simple string type.
The next type we talk about is the integer type. Look at :2
, which is the result returned by the INCR
command. The colon before the number indicates this is an integer.
Sometimes, the server may return an error type message beginning with a minus when a non-existent command has been processed, such as the got
command shown previously.
In addition, for the consideration of performance, you may send multiple commands in a single call to the Redis Server using RESP.
To sum up, the client sends commands to a Redis Server as a RESP array of bulk strings. Then the server replies with one of the five aforementioned RESP types accordingly.
- Refer to https://redis.io/topics/protocol for a more detailed description of the Redis protocol.
- Various kinds of Redis clients and proxies can be found on GitHub. For example, you can refer to https://github.com/tonivade/resp-server for a Java Netty implementation of RESP.
- Another example is https://github.com/tidwall/resp which contains reader, writer, and server implementations for the RESP in Golang.