RESP (Redis Serialization Protocol)

Table of Contents

1. RESP 协议

Redis 客户端使用 RESP (REdis Serialization Protocol) 协议与 Redis 的服务器端进行通信。

1.1. “请求—响应”模型

一般地,Redis 客户端和服务器之间的协议类似于 HTTP,是一种“请求—响应”协议。服务器接收到客户端的命令后,进行处理,处理完成后发送响应给客户端。但有两种例外情况:
1、Redis 支持管道操作(参见 Using pipelining to speedup Redis queries),客户端一次发送“多个”命令给服务器,服务器处理完后统一返回。
2、当Redis客户端订阅 Pub/Sub 模式的通道时,协议会改变语义变成“推送协议”,也就是说,客户端不再需要发送命令,因为服务器一旦收到消息就会自动向订阅了通道的客户端发送该新消息。

除了上述两个例外,Redis 协议就是一个简单的“请求—响应”协议。

2. RESP2 数据类型

RESP 的数据类型取决于第一个字节,RESP2 支持 5 种数据类型,如表 1 所示。

Table 1: RESP2 中的 5 种数据类型
第一个字节 含义 实例 说明
+ 简单字符串 +OK\r\n 字符串 OK
- 错误 -ERR unknown command 'foobar'\r\n 错误 ERR unknown command 'foobar'
: 整数 :5\r\n 整数 5
$ Bulk String $6\r\nfoobar\r\n Bulk String foobar, $ 后面紧跟字符串长度(这里是 6),所以二进制安全
* 数组 *3\r\n:5\r\n:6\r\n$6\r\nfoobar\r\n 数组有三元素,分别为整数 5,6 及 Bulk String foobar , * 后面紧跟元素个数

在 RESP 协议中,协议的不同部分始终以 \r\n 分隔(或结尾)。客户端发往服务器发送消息的类型只有一种:“Bulk String”的数组(后文将举例介绍它),而服务器返回给客户端的消息可能是表 1 中的任何一种数据。

2.1. 协议分析实例

下面以客户端发送 set a 1 给服务器,服务器返回 OK 为例分析一下 RESP 协议。

127.0.0.1:6379> set a 1
OK

首先,分析一下客户端发给服务器的数据。前面介绍过,客户端发往服务器发送消息的类型只有一种:“Bulk String”的数组。所以,命令 set a 1 需要编码为一个数组,且它的每个元素都是 Bulk String 类型。

第一个元素 set 用 Bulk String 表达就是 $3\r\nset\r\n ,类似地,第二个元素 a 用 Bulk String 表达为 $1\r\na\r\n ;第三上元素 1 用 Bulk String 表达为 $1\r\n1\r\n 。从而,命令 set a 1 可编码为 *3\r\n$3\r\nset\r\n$1\r\na\r\n$1\r\n1\r\n ,一共有 27 个字节,使用十六进制表示就是:

// 客户端执行 set a 1 时,发送给服务器的数据
2a 33 0d 0a 24 33 0d 0a 73 65 74 0d 0a 24 31 0d
0a 61 0d 0a 24 31 0d 0a 31 0d 0a

然后,分析一下服务器返回给客户端的数据。服务器返回简单字符串 OK,编码为 +OK\r\n ,一共有 5 个字节,使用十六进制表示就是:

2b 4f 4b 0d 0a

需要指出的是,客户端发送给服务器的所有命令都是“Bulk String”的数组,不管这个命令有没有参数。比如,命令 bgsave 是没有参数的,执行它时,也把它看作是“Bulk String”的数组(只有一个元素),客户端发送给服务器的编码为 *1\r\n$6\r\nbgsave\r\n ,一共 16 个字节,使用十六进制表示就是:

// 客户端执行 bgsave 时,发送给服务器的数据
2a 31 0d 0a 24 36 0d 0a 62 67 73 61 76 65 0d 0a

2.2. 内联命令

如果你手头没有专门的 Redis 客户端,那么你也可以使用 telnet 工具直接和 Redis 服务器交互。Redis 服务器也接受人类理解的命令形式,并被称为“内联命令”格式。

$ telnet localhost 6379
Connected to localhost.
Escape character is '^]'.
set a 1
+OK

在 telnet 中输入 set a 1 后回车,发送给服务器的数据如下:

73 65 74 20 61 20 31 0d 0a

Redis 服务器可以正确分析上面命令,并给出响应。

3. RESP3 数据类型

RESP3 除了支持 RESP2 中的 5 种数据类型外,还新增了表 2 所示的数据类型。

Table 2: RESP3 新增的数据类型
第一个字节 含义 实例(格式) 说明
_ Null 类型 固定写为 _\r\n 可代替 RESP2 中的 $-1\r\n*-1\r\n
, 双精度浮点数 ,1.23\r\n 浮点数 1.23
# 布尔类型 #t\r\n, #f\r\n 分别为 true 和 false
! Blob error 和 Bulk String 类似,用 ! 代替 Bulk String 的 $ 二进制安全的错误消息
= Verbatim string 和 Bulk String 类似,用 = 代替 Bulk String 的 $ 二进制安全的字符串,可以指定文本格式 txt/mkd
% Map 和数组类似,用 % 代替数组的 * 有序的键值对
~ Set 和数组类似,用 ~ 代替数组的 * 无序的不重复的集合
| Attribute 和 Map 类似,用 | 代替 Map 的 % 类似 Map 类型
> Push 和数组类似,用 > 代替数组的 * 带外数据,格式类似数组
( 大于 64bit 的数字 (3492890328409238509324850943850943825024385\r\n  

Author: cig01

Created: <2018-12-16 Sun>

Last updated: <2019-12-27 Fri>

Creator: Emacs 27.1 (Org mode 9.4)