I met RESP

When we want to implement a Redis server, we must first understand the redis communication protocol.

Redis author believes that the bottleneck of database system generally does not lie in network traffic, so he uses a simple plain text communication Protocol called RESP(Redis Serialization Protocol).

RESP is short for Redis serialization protocol. It is an intuitive text protocol with the advantage of exceptionally simple implementation and excellent parsing performance.

RESP defines five types of data structures, with each smallest unit separated by \r\n.

  • Simple string with+Character beginning, followed by string body.
  • Error message with-Character, followed by the error message body.
  • An integer value to:A string beginning with a character followed by an integer.
  • Complex strings (up to 512 MB)$Character start followed by string length; Followed by the string ontology.
  • Array to*Character, followed by the length of the array; And then the array element.

Like a simple string:

"+OK\r\n"
Copy the code

Error message:

"-Error message\r\n"
Copy the code

Integer:

":1000\r\n"
":0\r\n"
Copy the code

Complex strings:

"$6 \ r \ nfoobar \ r \ n" "$0 \ r \ n \ r \ n" "$1 \ r \ n" / / length of 1 is nullCopy the code

Array:

"* 0 \ r \ n" "$3 * 2 \ r \ n \ r \ nfoo \ r \ n $3 \ r \ nbar \ r \ n", "* 3 \ r \ n: 1 \ r \ n: 2 \ r \ n: 3 \ r \ n", "* 1 \ r \ n" / / length of 1 is null. For example, when blPOP times out, it should be returned and the client should display it as NULL.Copy the code

Arrays can be mixed types, such as arrays, with each line separated as follows:

*2\r\n
*3\r\n
:1\r\n
:2\r\n
:3\r\n
*2\r\n
+Foo\r\n
-Bar\r\n
Copy the code

The state machine

RESP is very simple and the definition of the protocol is very limited. So to implement a Redis Server, we can read the client request data line by line and parse it line by line.

We can draw a state machine based on the different states that the client’s row data arrives at.


Starting from the S state (the start state), the three simplest one-line data structures are the simple string, the error message, and the integer if the string is received with + or – or:. So you go to state A, and then you receive any value, you go to state END, which means that A request has been received.

If the $sign is received, the B state is entered. If -1 is received, it is null, and the reception ends. If it receives 0 or a positive integer, it enters the C state. At this time, it also receives any row of data and enters the END state, indicating the END.

If you receive an asterisk, which represents an array, things get a little more complicated. If you enter the D state, you will not receive a new line if you receive 0 or -1, and the request ends. If a natural value n is received at this time, it means that the array length is N, then it enters En state and restarts a state machine in S state until the state machine reaches END state, and n can be decreased by 1. When n is 0, the state becomes END.

Python implementation

The RESP state machine implementation section is slightly longer and limited to article length which has been placed on GitHub:

Github.com/sljeff/pyth…

Redis server is implemented directly using Python’s TCPServer:

# redis_server.py
from socketserver import TCPServer, StreamRequestHandler
from resp import handle_line
​
​
class RedisHandler(StreamRequestHandler):
    def handle(self):
        state = None
        while True:
            data = self.rfile.readline().strip()
            print(data)
            state = handle_line(data, state)
            if state.is_stoped:
                break
        self.wfile.write(b'+OK\r\n')
        print('end')
​
​
if __name__ == '__main__':
    host, port = 'localhost', 6379
    with TCPServer((host, port), RedisHandler) as server:
        server.serve_forever()
Copy the code

Now no matter what request comes in, the server responds +OK\r\n to the client. Our server side will also print out each line of requested characters.

Running effect

Type python redis_server.py directly to run the code; Install Redis – CLI as client.

When you type in redis-cli, you can see that the client sends an array of length 1 with a single string called COMMAND:


We type the command get a in redis-cli, and the client sends get and A to the server as an array of length 2. Of course, our server can only respond OK to the client right now.



This series may continue to be updated…

Project address: github.com/sljeff/pyth…

Welcome to star