RedisProtocol-redis协议翻译

2021/9/29 19:12:05

本文主要是介绍RedisProtocol-redis协议翻译,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

https://redis.io/topics/protocol/  原文地址

为了更好的理解redis协议,借助百度翻译和自己理解翻译了这篇文章。
redis协议确实够简单,容易理解。
********************************************************************************************
Redis Protocol specification  redis协议描述

Redis clients communicate with the Redis server using a protocol called RESP (REdis Serialization Protocol). 
While the protocol was designed specifically for Redis, it can be used for other client-server software projects.
RESP is a compromise between the following things:
redis客户端桶redis服务器通过一个种叫做RESP(redis序列化协议)的协议交流。
虽然这个是专门为redis设计的,但是其他的客户端服务器软件项目也可以使用。
RESP协议是以下几点(三点)的折中设计:
Simple to implement. 实现够简单
Fast to parse.  分析起来快
Human readable. 可读性好

RESP can serialize different data types like integers, strings, arrays. There is also a specific type for errors. 
Requests are sent from the client to the Redis server as arrays of strings representing the arguments of the command to execute.
Redis replies with a command-specific data type.
RESP协议可以序列化不同的数据类型,比如整数,字符串,数组。还有一种为了错误设计的特别类型。
请求以字符串数组的形式从客户端发送到Redis服务器,这些字符串表示要执行命令的参数。
redis用命令特有的数据类型回复(不同请求命令的回复都有不同的标志)。

RESP is binary-safe and does not require processing of bulk data transferred from one process to another, 
because it uses prefixed-length to transfer bulk data.
RESP协议是一种二进制安全并且不需要处理从一个进程传输到另一个进程块数据。
因为它使用前缀长度来传播块数据(一开始就指明了要传输数据的长度,通过长度直接获取块数据)。

Note: the protocol outlined here is only used for client-server communication. 
Redis Cluster uses a different binary protocol in order to exchange messages between nodes.
注意: 这里的协议只是用来客户端和服务器之间的交流。
Redis集群使用了不同的二进制协议,目的是为了在不同的节点的交换信息

Networking layer 网络层
A client connects to a Redis server creating a TCP connection to the port 6379.
一个客户端通过在端口号6379上创建一个TCP连接来连接Redis服务器

While RESP is technically non-TCP specific, in the context of Redis the protocol is only used with TCP connections 
(or equivalent stream oriented connections like Unix sockets).
虽然RESP协议非TCP特定的技术协议,但在Redis上下文中,该协议只在TCP连接中使用
(或者等价面向流的连接,类似UNIX套接字)

Request-Response model 请求-响应模型
Redis accepts commands composed of different arguments. Once a command is received, 
it is processed and a reply is sent back to the client.
Redis接收由不同参数构成的命令。一旦一个命令被接收,它就被处理然后就会给客户端一个回复

This is the simplest model possible, however there are two exceptions:
这个或许是最简单的模型,但是这里有两个意外:

Redis supports pipelining (covered later in this document). So it is possible for clients to send multiple commands at once, 
and wait for replies later.
redis支持管道(稍后在本文档中提及)。因此客户端一次发送多个命令然后等待回复是可能的,

When a Redis client subscribes to a Pub/Sub channel, the protocol changes semantics and becomes a push protocol,
that is, the client no longer requires sending commands, 
because the server will automatically send to the client new messages (for the channels the client is subscribed to) 
as soon as they are received.
当一个redis客户端订阅一个 发布/订阅 的频道,协议改变了原来的语义(发送协议)变成了一个推送协议,
那就是说,客户端不在需要发送请求命令,因为服务端一旦收到(新消息)会尽快自动给客户端发送这个新消息(对于客户端订阅的频道)

Excluding the above two exceptions, the Redis protocol is a simple request-response protocol.
除去上述两条意外,redis协议是一个简单的请求-相应协议

RESP protocol description RESP协议描述
The RESP protocol was introduced in Redis 1.2, but it became the standard way for talking with the Redis server in Redis 2.0. 
This is the protocol you should implement in your Redis client.
RESP协议是在redis1.2版本引入的,但是直到2.0版本,它才成为与redis服务器交流的标准方式。

RESP is actually a serialization protocol that supports the following data types: Simple Strings, Errors, 
Integers, Bulk Strings and Arrays.
RESP协议实际上是一个序列化协议,它支持以下的数据类型:简单字符串,错误,整数,块字符串 和 数组。

The way RESP is used in Redis as a request-response protocol is the following:
RESP协议在redis中使用的方式是一种请求-相应协议,如下所示:
Clients send commands to a Redis server as a RESP Array of Bulk Strings.
The server replies with one of the RESP types according to the command implementation.
In RESP, the type of some data depends on the first byte:
客户端将命令作为块字符串的RESP数组发送给redis服务器。
服务器根据命令的实现使用一种RESP类型回复(客户端)。
在RESP协议,一个写数据的类型取决于第一个字节:
For Simple Strings the first byte of the reply is "+"
对于简单的字符串,回复的第一个字节是"+"
For Errors the first byte of the reply is "-"
对于错误,回复的第一个字节是"-"
For Integers the first byte of the reply is ":"
对于整数,回复的第一个字节是":"
For Bulk Strings the first byte of the reply is "$"
对于字符串块,回复的第一个字节是"$"
For Arrays the first byte of the reply is "*"
对于数组,回复的第一个字节是"*"
Additionally RESP is able to represent a Null value using a special variation of Bulk Strings or Array as specified later.
另外RESP协议可以使用一个下面名确规定的特殊块字符串或者数组表示的特殊变量来表示一个空值,

In RESP different parts of the protocol are always terminated with "\r\n" (CRLF).
在RESP协议中,不同部分的协议总是用"\r\n"(回车换行)来终止。

RESP Simple Strings  RESP协议的简单字符串
Simple Strings are encoded in the following way: a plus character, 
followed by a string that cannot contain a CR or LF character (no newlines are allowed), terminated by CRLF (that is "\r\n").
简单字符串下一使用如下方式编码:
一个+字符,接下来是一个字符串但是不能包括回车或者换行(不能有新行),最后以回车换行结束.

Simple Strings are used to transmit non binary safe strings with minimal overhead. 
For example many Redis commands reply with just "OK" on success, 
that as a RESP Simple String is encoded with the following 5 bytes:
简单字符串被用来以最小的代价传输非二进制安全的字符串。
举例来说,很多redis命令成功时使用"OK" 来回复
"+OK\r\n"
In order to send binary-safe strings, RESP Bulk Strings are used instead.
为了使用二进制安全的字符串,RESP协议使用字符串块来代替(简单字符串)

When Redis replies with a Simple String, 
a client library should return to the caller a string composed of the first character after the '+' up to the end of the string, 
excluding the final CRLF bytes.
当redis服务器用简单字符串回复,
客户端库应该向调用者返回一个字符串,该字符串由“+”后面的第一个字符直到字符串的末尾,不包括最后的CRLF字节组成。


RESP Errors RESP协议的错误
RESP has a specific data type for errors. Actually errors are exactly like RESP Simple Strings, 
but the first character is a minus '-' character instead of a plus. 
The real difference between Simple Strings and Errors in RESP is that errors are treated by clients as exceptions, 
and the string that composes the Error type is the error message itself.
RESP有一个专门用于错误的数据类型。实际上错误与RESP协议的简单字符串完全类似,只是第一个字符是一个'-'号,代替了简答字符串的‘+’号。
简单字符串和错误在RESP协议中实际上的差别是,错误被客户单当做异常对待,并且组成错误类型的字符串就是错误信息本身。

The basic format is: 基本格式如下:

"-Error message\r\n"
Error replies are only sent when something wrong happens, 
for instance if you try to perform an operation against the wrong data type, or if the command does not exist and so forth. 
An exception should be raised by the library client when an Error Reply is received.
只有当一些错误事情发生时,错误回复才被发送,
举例来说,如果你尝试对一个错误的数据类型执行一个操作,或者如果命令不存在等等,
当客户端收到一个错误回复信息时,一个异常就会被客户端库抛出。

The following are examples of error replies: 下面是错误回复的一些例子:

-ERR unknown command 'foobar'
-WRONGTYPE Operation against a key holding the wrong kind of value

The first word after the "-", up to the first space or newline, represents the kind of error returned. 
This is just a convention used by Redis and is not part of the RESP Error format.
在减号后的第一个字,知道第一个空格或者新行,代表了返回的错误类型。
这只是Redis使用的约定,不是RESP协议错误格式的一部分。

For example, ERR is the generic error,  
while WRONGTYPE is a more specific error that implies that the client tried to perform an operation against the wrong data type. 
This is called an Error Prefix and is a way to allow the client to understand the kind of error 
returned by the server without to rely on the exact message given, that may change over the time.
举例来说,ERR是一般或的错误,而WRONGTYPE是一个更加明确的错误,意味着客户端尝试去对错误的数据类型执行一个操作。
这个叫做错误前缀,也是一种让客户端理解服务器返回的错误类型的方法,无需依赖给定的准确,因为这个消息会随时变化

A client implementation may return different kind of exceptions for different errors, 
or may provide a generic way to trap errors by directly providing the error name to the caller as a string.
客户端会根据不同的错误实现不同的异常返回,或者通过直接将错误名称作为字符串提供给调用方来提供捕获错误的通用方法。

However, such a feature should not be considered vital as it is rarely useful, 
and a limited client implementation may simply return a generic error condition, such as false.
但是这样的功能不应该被认为是关键的,因为它很少使用,
有限的客户端实现可能只返回一个通用的错误条件,例如false

RESP Integers  RESP协议的整数
This type is just a CRLF terminated string representing an integer, prefixed by a ":" byte. 
For example  ":0\r\n",  or ":1000\r\n" are integer replies.
这种类型只是由回车换行结束的字符串表示的整数,前缀是一个":"字节。
举例来说 ":0\r\n",  or ":1000\r\n" 都是整数回复.

Many Redis commands return RESP Integers, like INCR, LLEN and LASTSAVE.
很多redis命令返回RESP协议的整数,例如 INCR, LLEN and LASTSAVE.

There is no special meaning for the returned integer, it is just an incremental number for INCR, 
a UNIX time for LASTSAVE and so forth. However, the returned integer is guaranteed to be in the range of a signed 64 bit integer.
对于返回的整数没有特殊意义,它只是INCR的增量,LASTSAVE的UNIX时间等等。但是,返回的整数保证在有符号64位整数的范围内。

Integer replies are also extensively used in order to return true or false. 
For instance commands like EXISTS or SISMEMBER will return 1 for true and 0 for false.
整数回复还广泛用于返回true或false。
例如,EXISTS或SISMEMBER等命令将返回1表示true,0表示false。

Other commands like SADD, SREM and SETNX will return 1 if the operation was actually performed, 0 otherwise.
其他命令(如SADD、SREM和SETNX),如果实际执行了操作,就返回1,否则返回0。

The following commands will reply with an integer reply: SETNX, DEL, EXISTS, INCR, INCRBY, DECR, DECRBY, 
DBSIZE, LASTSAVE, RENAMENX, MOVE, LLEN, SADD, SREM, SISMEMBER, SCARD.
以下命令将以整数答复:SETNX, DEL, EXISTS, INCR, INCRBY, DECR, DECRBY, 
DBSIZE, LASTSAVE, RENAMENX, MOVE, LLEN, SADD, SREM, SISMEMBER, SCARD.

RESP Bulk Strings RESP协议的 字符串块
Bulk Strings are used in order to represent a single binary safe string up to 512 MB in length.
字符串块用于表示长度不超过512 MB的单个二进制安全字符串。

Bulk Strings are encoded in the following way: 字符串块用以下方式来编码:
A "$" byte followed by the number of bytes composing the string (a prefixed length), terminated by CRLF.
一个“$”字节,后跟组成字符串的字节数(前缀长度),以CRLF结尾。
The actual string data. 实际的字符串数据
A final CRLF. 最后的回车换行
So the string "foobar" is encoded as follows: 因此字符串"foobar"被编码成如下方式:
"$6\r\nfoobar\r\n"
When an empty string is just: 空字符串编码如下:
"$0\r\n\r\n"

RESP Bulk Strings can also be used in order to signal non-existence of a value using a special format 
that is used to represent a Null value. In this special format the length is -1, and there is no data, 
so a Null is represented as:
也可以使用RESP协议的字符串块 使用特殊格式表示不存在值,那就是用于表示空值。
在这种特殊格式中,长度为-1,没有数据,因此空值可以表示为:
"$-1\r\n"
This is called a Null Bulk String. 这个叫做一个空的字符串块

The client library API should not return an empty string, but a nil object, when the server replies with a Null Bulk String. 
For example a Ruby library should return 'nil' while a C library should return NULL (or set a special flag in the reply object), 
and so forth.
当服务器以空字符串块答复时,客户端库API不应返回空字符串,而应返回nil对象。
例如,Ruby库应该返回'nil',而C库应该返回NULL(或者在回复对象中设置一个特殊标志),等等。

RESP Arrays RESP协议的数组
Clients send commands to the Redis server using RESP Arrays. 
Similarly certain Redis commands returning collections of elements to the client use RESP Arrays are reply type. 
An example is the LRANGE command that returns elements of a list.
客户端使用RESP协议数组发送命令给redis服务器。
类似地,某些向客户端返回元素集合的Redis命令使用RESP数组当做回复类型。
一个例子就是LRANGE命令,返回一个元素的列表。

RESP Arrays are sent using the following format: RESP协议的数组使用如下格式发送:

A * character as the first byte, followed by the number of elements in the array as a decimal number, followed by CRLF.
'*'字符作为第一个字节,后跟随一个十进制数,该数表示数组中元素的个数,最后是回车换行。
An additional RESP type for every element of the Array.
数组中的每个元素都是一个单独的RESP协议类型

So an empty Array is just the following:  因此一个空的数组如下

"*0\r\n"

While an array of two RESP Bulk Strings "foo" and "bar" is encoded as:
两个字符串"foo" 和 "bar" 组成的字符串块编码如下:
"*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n"

As you can see after the *<count>CRLF part prefixing the array, 
the other data types composing the array are just concatenated one after the other. 
For example an Array of three integers is encoded as follows:
正如你所见,在数组前缀部分*<count>CRLF之后,构成数组的其他数据类型只是一个接一个地连接在一起。
例如,三个整数的数组编码如下:
"*3\r\n:1\r\n:2\r\n:3\r\n"

Arrays can contain mixed types, it's not necessary for the elements to be of the same type. 
For instance, a list of four integers and a bulk string can be encoded as the follows:
数组可以包含混合类型,元素不必是同一类型。例如,四个整数和一个字符串块的列表可以按如下方式编码:

*5\r\n
:1\r\n
:2\r\n
:3\r\n
:4\r\n
$6\r\n
foobar\r\n
(The reply was split into multiple lines for clarity).为了清楚起见,答复分成多行

The first line the server sent is *5\r\n in order to specify that five replies will follow. 
Then every reply constituting the items of the Multi Bulk reply are transmitted.
服务器发送的第一行是*5\r\n,其中的5指定随后将有五个答复。
然后,每个答复组合构成的多块回复被传送。

The concept of Null Array exists as well, and is an alternative way to specify a Null value 
(usually the Null Bulk String is used, but for historical reasons we have two formats).
空数组的概念也存在,并且是指定空值的另一种方法
(通常使用空字符串块,但出于历史原因,我们有两种格式)。
For instance when the BLPOP command times out, it returns a Null Array that has a count of -1 as in the following example:
例如,当BLPOP命令超时时,它返回一个计数为-1的空数组,如下例所示:
"*-1\r\n"

A client library API should return a null object and not an empty Array when Redis replies with a Null Array. 
This is necessary to distinguish between an empty list and a different condition 
(for instance the timeout condition of the BLPOP command).
当Redis使用空数组回复时,客户端库API应该返回空对象而不是空数组。
这是区分空列表和不同条件(空对象)所必需的(例如BLPOP命令的超时条件)。

Arrays of arrays are possible in RESP. For example an array of two arrays is encoded as follows:
数组的数组在RESP协议中是可能的。例如,包含两个数组的数组编码如下:

*2\r\n
*3\r\n
:1\r\n
:2\r\n
:3\r\n
*2\r\n
+Foo\r\n
-Bar\r\n
(The format was split into multiple lines to make it easier to read).格式被分成多行,以便于阅读。

The above RESP data type encodes a two elements Array consisting of an Array 
that contains three Integers 1, 2, 3 and an array of a Simple String and an Error.
上述RESP协议的数据类型编码由两个数组组成,一个数组包含三个整数1、2、3,
另外一个数组包含一个简单字符串和一个错误信息。

Null elements in Arrays 数组中的空元素
Single elements of an Array may be Null. This is used in Redis replies in order to signal 
that these elements are missing and not empty strings. 
数组的单个元素可以为空。这在Redis回复中用于表示这些元素丢失且不是空字符串
This can happen with the SORT command when used with the GET pattern option when the specified key is missing. 
Example of an Array reply containing a Null element:
这种情况可能发生在,当使用GET模式选项执行SORT命令时,特定的键丢失。
包含空元素的数组回复示例:

*3\r\n
$3\r\n
foo\r\n
$-1\r\n
$3\r\n
bar\r\n
The second element is a Null. The client library should return something like this:
第二个元素是空。客户端库应返回如下内容:
["foo",nil,"bar"]

Note that this is not an exception to what was said in the previous sections, 
but just an example to further specify the protocol.
请注意,这并非前几节所述的异常,这只是一个进一步说明协议的示例。

Sending commands to a Redis Server 发送命令给redis服务器
Now that you are familiar with the RESP serialization format, 
writing an implementation of a Redis client library will be easy. 
We can further to specify how the interaction between the client and the server works:
现在你已经熟悉了RESP协议序列化格式,编写Redis客户端库的实现将很容易。
我们可以进一步指定客户端和服务器之间的交互方式:

A client sends the Redis server a RESP Array consisting of just Bulk Strings.
A Redis server replies to clients sending any valid RESP data type as reply.
So for example a typical interaction could be the following.
客户端向Redis服务器发送一个仅由字符串块组成的RESP协议数组。
Redis服务器发送任何具有有效RESP协议数据类型回复客户端。
例如,一个典型的交互可能如下所示。

The client sends the command LLEN mylist in order to get the length of the list stored at key mylist, 
and the server replies with an Integer reply as in the following example (C: is the client, S: the server).
客户端(向服务器)发送命令LLEN mylist以获取存储在键mylist中的列表长度,
然后服务器用一个整数回复,如下例所示(C:是客户端,S:服务器)

C: *2\r\n
C: $4\r\n
C: LLEN\r\n
C: $6\r\n
C: mylist\r\n

S: :48293\r\n

As usual we separate different parts of the protocol with newlines for simplicity, 
but the actual interaction is the client sending *2\r\n$4\r\nLLEN\r\n$6\r\nmylist\r\n as a whole.
通常为了方便阅读,我们用新行分隔协议的不同部分,
但实际的交互是客户端将*2\r\n$4\r\nLen\r\n$6\r\nmylist\r\n作为一个整体发送(给服务器)。

Multiple commands and pipelining  多命令和管道(这里就是上文说说的会提及的管道)
A client can use the same connection in order to issue multiple commands. 
客户端可以使用相同的连接来发出多个命令。
Pipelining is supported so multiple commands can be sent with a single write operation by the client, 
without the need to read the server reply of the previous command before issuing the next one. 
All the replies can be read at the end.
管道操作被支持,因此客户端可以通过一次写入操作发送多个命令,
无需在发出下一个命令之前读取上一个命令的服务器回复。
所有命令的服务器回复可以在最后被读取。

For more information please check our page about Pipelining.
想了解更多信息,请查看我们关于管道的网页。

Inline Commands 内联命令
Sometimes you have only telnet to hand and you need to send a command to the Redis server. 
While the Redis protocol is simple to implement it is not ideal to use in interactive sessions, 
and redis-cli may not always be available. 
For this reason Redis also accepts commands in a special way that is designed for humans, 
and is called the inline command format.
有时你手头只有telnet可以使用,需要向Redis服务器发送命令。
虽然Redis协议易于实现,但在交互式会话中使用并不理想,而且redis客户端可能并不总是可用。
因此,Redis还为人们设计通过特殊的渠道接收命令,称为内联命令格式。

The following is an example of a server/client chat using an inline command
(the server chat starts with S:, the client chat with C:)
下面是使用内联命令进行服务器/客户端聊天的示例(服务器聊天以S:开始,客户端聊天以C:开始)

C: PING
S: +PONG

The following is another example of an inline command returning an integer:
以下是返回整数的内联命令的另一个示例:

C: EXISTS somekey
S: :0

Basically you simply write space-separated arguments in a telnet session. 
Since no command starts with * that is instead used in the unified request protocol, 
Redis is able to detect this condition and parse your command.
基本上,你只需在telnet会话中编写以空格分隔的参数。
由于统一请求协议中没有以*开头的命令,所以Redis能够检测到这种情况并解析你的命令。

High performance parser for the Redis protocol 
Redis协议的高性能解析器
While the Redis protocol is very human readable and easy to implement it can be implemented with a performance similar to 
that of a binary protocol.
Redis协议不但非常容易实现,易于阅读,而且可以以类似于二进制协议的性能实现。

RESP uses prefixed lengths to transfer bulk data, 
so there is never a need to scan the payload for special characters like it happens for instance with JSON, 
nor to quote the payload that needs to be sent to the server.
RESP协议使用前缀长度传输块数据,因此,无需像JSON那样扫描负载中的特殊字符(通过特殊字符来确定开始结束位置),
也不需要将发送到服务器的有效负载用引号引起来(也是为了确定开始和结束位置)。

The Bulk and Multi Bulk lengths can be processed with code that performs a single operation per character 
while at the same time scanning for the CR character, like the following C code:
块和多个块的长度可以使用对每个字符执行单个操作的代码进行处理
同时扫描CR(回车)字符,如以下C代码所示:

#include <stdio.h>

int main(void) {
    unsigned char *p = "$123\r\n";
    int len = 0;

    p++;
    while(*p != '\r') { 不遇到回车符号,继续往下
        len = (len*10)+(*p - '0');
        p++;
    }

    /* Now p points at '\r', and the len is in bulk_len. */ 现在指针p指向符号回车,变量len就是块长度
    printf("%d\n", len);
    return 0;
}
After the first CR is identified, it can be skipped along with the following LF without any processing. 
Then the bulk data can be read using a single read operation that does not inspect the payload in any way. 
Finally the remaining the CR and LF character are discarded without any processing.
在识别出第一个CR(回车符号)后,可以将其与下一个符号LF(换行)一起跳过,而无需任何处理。
然后,可以使用不以任何方式检查有效负载的单个读取操作来读取数据块。最后,剩余的CR和LF字符将被丢弃,无需任何处理。


While comparable in performance to a binary protocol 
the Redis protocol is significantly simpler to implement in most very high level languages, 
reducing the number of bugs in client software.

redis协议不但在性能上与二进制协议相当,而且Redis协议在大多数高级语言中实现起来要简单得多,因此会减少客户端软件中的bug数量。

********************************************************************************************

 



这篇关于RedisProtocol-redis协议翻译的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程