redis传输协议规范(翻译)-上(Redis Protocol specification)

Redis客户端使用一个称为RESP的协议与Redis服务器通信。虽然该协议是专门为Redis设计的,但它也可以用作其他客户端-服务器软件项目的通信协议。
RESP协议在以下几点之间做了折中:
  • 易于实现
  • 方便计算机快速解析
  • 方便人阅读
RESP协议可以序列化不同的数据类型,如整数、字符串、数组。错误也有一个特定的类型。带有参数的请求从客户端以字符串数组的形式发送到Redis服务器。Redis以命令对应的数据类型进行回复。
RESP是二进制安全的,并且不需要处理从一个进程传输到另一个进程的大块数据,因为它使用预定义的长度来传输大块数据。
注意:这里列出的协议仅用于客户端-(单实例)服务器通信。Redis集群在节点之间交换信息则使用了不同的协议。
 

网络层面

客户端使用TCP协议连接到Redis服务器的6379端口。
虽然RESP并非只能在TCP上使用,但在Redis相关的文档里,如果没有特殊说明,RESP默认使用TCP协议(或等效的面向流的连接,如Unix socket)。
 

请求-响应模型

Redis接收由不同参数组成的命令。一旦接收到命令,redis就会对其进行处理,并将回复发送回客户端。
这可能是最简单的模型,但是有两个例外:
  • Redis支持pipelining(稍后将在本文档中介绍)。所以客户端可以一次发送多个命令,然后等待服务器的响应。
  • 当一个Redis客户端订阅一个Pub/Sub通道时,该协议会改变语意而变成一个推送协议,也就是说,客户端不再需要发送命令,因为服务器一旦接收到新消息(针对客户端订阅的通道),就会自动发送给客户端。
除了以上两个例外,Redis协议就是一个简单的请求-响应协议。
 

RESP协议规范

RESP协议是在Redis 1.2中引入的,但在Redis 2.0中它成为了与Redis服务器通信的标准方式。RESP协议是你应该在Redis客户端实现的协议。
RESP实际上是一个序列化协议,它支持以下数据类型:简单字符串、错误、整数、大块字符串和数组。
RESP在Redis中用作请求-响应协议的方式如下:
  • 客户端使用大块字符串(bulk strings也可翻译为大容量字符串,本文使用大块字符串)数组格式发送命令到Redis服务器。
  • 服务器根据命令实现的RESP类型进行响应。
在RESP协议中,数据的类型取决于第一个字节:
  • 对于简单字符串,回复的第一个字节是“+”
  • 对于错误,回复的第一个字节是“-”
  • 对于整数,回复的第一个字节是“:”
  • 对于大块字符串(大容量字符串bulk strings),回复的第一个字节为"$"
  • 对于数组回复的第一个字节是"*”
此外,RESP还能够使用后面指定的批量字符串或数组的特殊变体来表示空值。
RESP协议以“\r\n”(CRLF)来区分协议中不同的部分。
 
 

RESP协议字符串

简单字符串按以下方式编码:一个加号,后跟紧跟着不能包含CR或LF字符(不允许换行)的字符串,以CRLF结束(即"\r\n")。
简单字符串用于以最小的开销传输非二进制安全字符串。例如,许多Redis命令回复只是“OK”成功,那作为一个简单的RESP字符串编码以下5个字节:
"+OK\r\n"

  

redis使用RESP批量字符串发送二进制安全的字符串。
当Redis回复一个简单的字符串时,客户端库应该返回给调用者一个字符串,该字符串由'+'后面的第一个字符到字符串的结尾,不包括最后的CRLF字节。
 

RESP协议错误

RESP给错误定义了一个特定的数据类型。实际上,错误就像RESP简单字符串类型,但是第一个字符是一个减号而不是加号。在RESP中,简单字符串和错误之间的真正区别在于,错误被客户端视为异常,而组成错误类型的字符串就是错误消息本身。
基本格式是:
"-Error message\r\n"

  

错误响应只在发生错误时发送,例如,如果您试图对错误的数据类型执行操作,或者请求的命令不存在,等等。当收到错误回复时,客户端库应该引发异常。
下面是一些错误回复的例子:
-ERR unknown command 'foobar' 
-WRONGTYPE Operation against a key holding the wrong kind of value

  

 
“-”之后的第一个单词,一直到第一个空格或换行符,表示返回的错误类型。这只是Redis使用的一个约定,并不是RESP错误格式的一部分。
例如,ERR是通用错误,而WRONGTYPE是更具体的错误,它意味着客户端试图对错误的数据类型执行操作。这被称为错误前缀,是一种允许客户端理解服务器返回的错误类型的方法,而不需要依赖于所给出的确切消息,这可能会随着时间的推移而改变。
客户端实现可以为不同的错误返回不同类型的异常,也可以通过直接将错误名称作为字符串提供给调用者来提供捕获错误的通用方法。
然而,这样的功能不应该被认为是至关重要的,因为它很少有用,而且缩减版的客户端实现可能仅仅返回一个通用的错误条件,比如false。
 

RESP整数

RESP整数类型只是一个以CRLF结尾的字符串,表示一个整数,前缀为“:”字节。例如,":0\r\n"或":1000\r\n"都是整数回复。
很多Redis命令返回RESP整数,如INCRLLEN 和LASTSAVE.
返回的整数没有特殊意义,它只是INCR的一个增量数,LASTSAVE的UNIX时间,等等。但是,返回的整数保证在有符号的64位整数的范围内。
整数响应也被广泛用于返回真或假。例如,像EXISTS或SISMEMBER这样的命令将返回true为1,false为0。
其他命令,如 SADDSREM and SETNX ,如果实际执行了操作,则返回1,否则返回0。
下面的命令将用一个整数回复:SETNXDELEXISTSINCRINCRBYDECRDECRBYDBSIZELASTSAVERENAMENXMOVELLENSADDSREMSISMEMBERSCARD
 
RESP大块字符串(bulk strings)
使用大块字符串(bulk strings)是为了表示长度不超过512 MB的单个二进制安全字符串。
大块字符串的编码方式如下:
  • 一个"$"字节,后面跟着组成字符串的字节数(有前缀的长度),以CRLF结束。
  • 实际的字符串数据。
  • 最后一个CRLF。
因此字符串foobar编码如下:
"$6\r\nfoobar\r\n"

  

当一个空字符串为:
"$0\r\n\r\n"

  

RESP大块字符串也可以用来表示值不存在,使用一种特殊的格式来表示空值。在这种特殊格式中,长度为-1,没有数据,因此Null表示为:
"$-1\r\n"

  

这被称为空大块字符串。
当服务器返回给客户端一个空的大块字符串时,客户端库API不应该返回给调用者一个空字符串,而应该返回一个nil对象。例如,Ruby库应该返回'nil',而C库应该返回NULL(或者在应答对象中设置一个特殊的标志),等等。
 
参考资料:
 

posted @ 2020-10-21 15:42  猿界汪汪队  阅读(105)  评论(0编辑  收藏  举报