type
status
date
slug
summary
tags
category
icon
password
网络层(Networking layer)请求-响应模型( Request-Response model)RESP 协议解释RESP Simple StringsRESP ErrorsRESP IntegersRESP Bulk StringsRESP Arrays发送命令到Redis服务器管道和多个命令内联命令
Redis Protocol specification – Redis
Redis客户端和服务器端通信使用名为 RESP (REdis Serialization Protocol) 的协议。虽然这个协议是专门为Redis设计的,它也可以用在其它 client-server 通信模式的软件上。
RESP 是下面条件的折中:
- 实现起来简单。
- 解析速度快。
- 有可读性。
RESP
能序列化不同的数据类型,例如整型(integers)、字符串(strings)、数组(arrays)。额外还有特殊的错误类型。请求从客户端以字符串数组的形式发送到redis服务器,这些字符串表示要执行的命令的参数。Redis用特定于命令的数据类型回复。RESP
是二进制安全的,并且不需要处理从一个进程发到另外一个进程的批量数据,因为它使用前缀长度来传输批量数据。注意:这里概述的协议仅用于客户机-服务器通信。Redis集群使用不同的二进制协议在节点之间交换消息。
网络层(Networking layer)
默认情况下,连到Redis服务器的客户端会建立了一个到
6379
端口的TCP连接。虽然RESP在技术上不特定于TCP,但是在Redis的上下文中,该协议仅用于TCP连接(或类似的面向流的连接,如unix套接字)。
请求-响应模型( Request-Response model)
Redis接受由不同参数组成的命令。一旦收到命令,就会对其进行处理,并将应答发送回客户端。
这是最简单的模型,但是有两个例外:
- 管道模式下。Redis 支持管道(pipelining)。所以,客户端可以一次发送多个命令,然后再等待应答。
- 发布订阅模式下。当一个Redis客户端订阅一个频道,那么协议会改变语义并变成
push protocol
, 也就是说,客户客户端不再需要发送命令,因为服务器端会一收到新消息,就会自动发送给客户端。
除了上面两个例外情况,Redis协议是一个简单的请求-响应协议。
RESP 协议解释
RESP 协议在Redis1.2被引入,直到Redis2.0才成为和Redis服务器通信的标准。
RESP
是一个支持多种数据类型的序列化协议:- 简单字符串(Simple Strings),也被翻译为“单行字符串”
- 错误( Errors)
- 整型( Integers)
- 大容量字符串(Bulk Strings),也被翻译为“多行字符串”
- 数组(Arrays)
如上图所示,
RESP
在Redis中作为一个请求-响应协议以如下方式使用:- 客户端以
Bulk Strings
组成的RESP Arrays
的方式发送命令给服务器端。
- 服务器端根据命令的具体实现返回某一种RESP数据类型。
RESP Simple Strings
编码方式:
- 加号 与 实际字符串 与 CRLF 结尾 =>
+
+实际字符串
+\r\n
例如:
注意:实际字符串中不允许包含回车换行符
如果需要发送二进制安全的字符串,应该选择使用RESP的大容量字符串(Bulk Strings)替代。
RESP Errors
编码方式:
- 减号 与 错误字符串 与 CRLF 结尾 =>
+
错误字符串
+\r\n
例如:
Errors 用于在发生异常时传输
RESP Integers
编码方式:
- 冒号 与 字符串形式的数字 与 CRLF 结尾 =>
:
+数字字符串
+\r\n
例如:
注意:返回的整数有效值需要在有符号64位整数范围内。
RESP Bulk Strings
编码方式由三部分组成:
- 第一部分:美元符号 与 组成字符串的字节数 与 CRLF 结尾
- 第二部分:实际的字符串数据
- 第三部分:CRLF 即为
例如:
为了便于显示,上面以换行处理各部分字符,实际中传输使用的是如下:
注意:
有两种特殊形式的 Bulk Strings:
- 空串(数据分布长度为0,表示空串"")
- Null Bulk String(在这种格式里长度值为-1,数据部分不存在,所以为Null)
大容量字符串被用来表示最长512MB的二进制安全字符串。
RESP Arrays
编码方式:
- 第一部分:星号 与 数组元素的个数的十进制数 与 CRLF 结尾
- 第二部分:数组中每个 RESP 类型的元素(按照上面提到的各种类型的编码方式)
示例:
- 空数组
- 正常数组
对应 [1,2,3]
- 带多种类型的嵌套数组
(为了方便阅读,分成多行来展示).
对应 [[1, 2, 3], ["Foo", "Bar"]]
- NULL数组(由于历史原因,还存在NULL 值的数组,通常使用 NULL Bulk Strings)
- 数组中的Null 元素
(为了方便阅读,分成多行来展示)
对应 ["foo", Null, "bar"]
发送命令到Redis服务器
至此,我们已经很熟悉RESP序列化格式,写一个Redis客户端库的实现会变得很容易。我们可以进一步说明客户端和服务端如何交互工作:
- 客户端发送包含只有多行字符串的数组给Redis服务器。
- Redis 服务器给客户端发送任意有效的 RESP 数据类型作为应答。
下面是一个典型的交互过程例子:
客户端发送命令
LLEN mylist
来获取存储在 mylist
键中列表的长读,然后服务器端返回整数应答(C: 代表客户端, S: 代表服务器端).为了方便理解我们用换行把协议分成不同部分,实际上客户端发送的是一个整体没有换行:
如果想体现使用RESP来编写命令的话,可以下载 netcat 工具体验一把。
首先需要有一个运行的 redis-server
然后就可以操作了
管道和多个命令
客户端可以使用同一个连接发送多个命令。通过管道客户端可以一次写操作发送多个命令,发送下一个命令前不需要等待前一个命令的应答。所有应答可以在最后被读取。
关于管道详细参考 page about Pipelining.
内联命令
有时你手边只能操作
telnet
并且需要给Redis 服务器端发送命令。虽然Redis协议是容易实现的,但并不适合用在交互会话。redis-cli
也不是随时都能可用。因此,redis还以一种特殊的方式接受为人类设计的命令,称为内联命令格式。以下是使用内联命令进行服务器/客户端聊天的示例(服务器聊天以s开头,客户端聊天以c开头)。
以下是返回整数的内联命令的另一个示例:
基本上,您只需在telnet会话中编写空格分隔的参数。由于统一请求协议中没有以*开头的命令,因此Redis能够检测到这种情况并解析您的命令。
- 作者:eachenkuang
- 链接:https://kuangyichen.com/article/resp
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。