TrumanWong

RESP 3协议

TrumanWong
5/14/2024

Redis服务端与客户端之间的通信协议为RESP(Redis Serialization Protocol)。RESP3Redis Serialization Protocol version 3)是Redis 6引入的一种新的通信协议,相对于其前身RESP2RESP3在多个方面进行了改进和增强。

RESP2协议

Redis 6.0版本前,Redis一直使用RESP 2协议。RESP 2协议有以下几个缺点:

  • 无论是列表还是有序集合,数据都是以字符串数组的形式返回给客户端,这增加了客户端解析实现的复杂性。在语义层,RESP 2无法让客户端感知到“合适的转化”(如需要返回key-value对的时候,服务端只能把keyvalue放一起用数组返回)。
  • 缺乏一些重要的数据类型。例如,浮点数和布尔值返回的是stringinteger类型。

RESP3协议

Redis 6.0升级了RESP协议,主要改进了以下方面:

  • 新增了多种数据类型。
  • 支持服务端主动推送数据的协议,这为实现客户端缓存奠定了基础。
  • 在请求的正常返回内容外,还支持返回一些其他属性,帮助客户端更好地统计、解析返回值。

RESP 3协议可分为简单类型和聚合类型,后者是前者的组合。RESP 3协议的基本格式如下:

标识符 数据 分隔符+换行符

以字符串为例,在RESP 3中返回”Hello World“的格式如下:

+Hello World\r\n

其中,+为一般字符串的标识符,hello world是数据内容。\r\n分别是分隔符和换行符,后续用<CR><LF>表示。

注意:默认协议为RESP 2,要想启用RESP 3协议,需执行hello 3命令。

RESP3数据类型

简单类型

当响应结果为字符串、整数等简单类型时,RESP 3采用简单类型表示。

二进制字符串blob string

二进制字符串用$作为标识符,第一行数据为长度,第二行数据为实际数据。

格式: $<length><CR><LF><bytes><CR><LF>。它基本上与RESP的早期版本完全相同。

示例:$11<CR><LF>HelloWorld<CR><LF>

二进制错误blob error

二进制错误用!作为标识符。

格式: !<length><CR><LF><bytes><CR><LF>

示例:!21<CR><LF>SYNTAX invalid syntax<CR><LF>

简单字符串simple string

格式: +<string><CR><LF>

示例:+HelloWorld<CR><LF>

简单错误simple error

格式: -Error<message><CR><LF>

示例:-Error message<CR><LF>

逐条字符串verbatim string

格式: =<length><CR><LF><bytes><CR><LF>

示例:=15<CR><LF>txt:Some string<CR><LF>

该类型在<bytes>开始时会用3个字符描述更详细的数据类型,如txtmkd等。第4个字节始终为:

整数Number

格式: :<number><CR><LF>

示例::1234<CR><LF>

有效数字在有符号64位整数的范围内。较大的数字应该改用大数字类型。

null

格式: _<CR><LF>

示例:_<CR><LF>

null没有数据标识符,_后直接为 CRLF

浮点数double

格式: ,<floating-point-number><CR><LF>

示例:,1.23<CR><LF>

布尔值boolean

布尔值用#作为标识符。true#tfalse#f

格式: #<bool><CR><LF>

示例:#t<CR><LF>

大数big number

大数用(作为标识符。

格式: (<big number><CR><LF>

示例:(341232321321221455465456678667876<CR><LF>

聚合类型

当响应结果为字典、集合等复杂数据类型时,RESP 3采用聚合类型表示。聚合类型格式类似JSON,可嵌套简单类型。其语法格式如下:

<aggregate-type-char><numelements><CR><LF> ... numelements other types ...

字典map type

字典用 %作为标识符,第一行数据为字典大小,后续行为key-value数据。key为简单字符串,value视情况而定(字符串或整数)。

格式: %<length><CR><LF>+<key><CR><LF>:<value><CR><LF>...

示例:%2<CR><LF>+first<CR><LF>:1<CR><LF>+second<CR><LF>:2<CR><LF>

集合set reply

集合用~作为标识符,第一行数据为集合大小,后续为集合数据。

格式:~<length><CR><LF>...

示例:

~5<CR><LF>
+orange<CR><LF>
+apple<CR><LF>
#t<CR><LF>
:100<CR><LF>
:999<CR><LF>

数组array

数组用*作为标识符,第一行数据为数组大小,后续为数组元素。

注意:数组可以嵌套

格式:*<length><CR><LF>...

示例:*3<CR><LF>:1<CR><LF>:2<CR><LF>:3<CR><LF>

属性类型attribute type

属性类型用|作为标识符,第一行数据为属性个数,后续为属性key-value

|1<CR><LF>
    +key-popularity<CR><LF>
    %2<CR><LF>
        $1<CR><LF>
        a<CR><LF>
        ,0.1923<CR><LF>
        $1<CR><LF>
        b<CR><LF>
        ,0.0012<CR><LF>
*2<CR><LF>
    :2039123<CR><LF>
    :9543892<CR><LF>

推送类型push type

推送类型是RESP 3较独特的类型,以>作为标识符。

格式:><length><CR><LF>...

示例:

>3<CR><LF>
+message<CR><LF>
+somechannel<CR><LF>
+this is the message<CR><LF>

hello

Hello是开启RESP 3协议的特殊命令。通过Hello 3Hello 2可切换RESP版本

格式:Hello <protocol version>

示例:hello 3