什么是 RESP
RESP
即 REdis Serialization Protocol 的简称,是 Redis 客户端与服务端通讯所使用的协议,传输层使用的是 TPC 协议,相比其他 RPC 通讯协议,RESP 有以下优点:
-
实现简单 -
解析高效 -
可读性好
初识 RESP
我们通过redis-cli
客户端执行PING
命令,看下 Redis 的返回结果
$ redis-cli -h localhost -p 6379 PING
PONG
不出意料,服务端返回 PONG,证明 Redis 服务正常运行。接着,我们使用Netcat
发送PING
命令,看看返回的结果有什么不同
$ echo "PING" | nc localhost 6379
+PONG
Netcat
是一款网络工具,可以很方便的从 TCP 套接字中发送/读取数据,这里可以与 Redis 进行交互,是因为 RESP 底层使用的也是 TCP 协议。不了解 Netcat 的话,可以看我之前的一篇文章《NetCat 介绍及使用》
可以看到,相比redis-cli
, Netcat
执行PING
命令的返回结果中,多了一个 +
号,这是为什么呢?
事实上,+PONG 才是 redis-server 返回的真正结果,因为客户端与服务端之间进行数据交互的时候,都要遵循 RESP 协议,RESP 协议规定,在每种数据类型的前面,都要增加一个额外的字节,用于区分不同的数据类型。比如用+
表示Simple Strings
类型。这也是为什么 Netcat 的返回结果为 +PONG 的原因,+
号表示返回结果是一个Simple Strings
类型,后面的PONG
则是Simple Strings
的内容
至于 redis-cli 返回结果 PONG,则是 redis-cli 解析后的结果
RESP 数据类型
在 RESP 中,总共定义了 5 种数据类型,分别是Simple Strings
、Errors
、Intergers
、Bulk Strings
和Arrays
,第一个字节与数据类型的映射关系如下:
-
Simple Strings
类型,第一个字节为+
-
Errors
类型,第一个字节为-
-
Integers
类型,第一个字节为:
-
Bulk Strings
类型,第一个字节为$
-
Arrays
类型,第一个字节为*
下面分别介绍这几种数据类型
简单字符串 Simple Strings
Simple Strings
是 Redis 中比较常见的数据类型,很多的响应用的都是Simple Strings
类型,的编码方式如下:
-
第一个字符为 +
-
紧接着是一个不能包含 CR
或LF
的字符串(不允许换行) -
以 CRLF
结束
Simple Strings
能保证在最小开销的情况下传输非二进制安全的字符串,比如很多Redis
命令执行成功都要返回OK
字符串,该字符串通过Simple Strings
编码为5
个字节的数据报如下
+OKrn
错误响应 Errors
Errors
用于返回异常信息,当 redis 命令执行错误的时候,就会返回Errors
类型的响应。Errors
的编码方式如下:
-
第一个字符为 -
-
紧接着是一个不能包含 CR
或LF
的字符串(不允许换行) -
以 CRLF
结束
可以看到,Errors
的编码方式和Simple Strings
很像,唯一的区别是Errors
的第一个字符是-
,下面是一个Errors
响应的例子
-ERR value is not an integer or out of rangern
整型 Integers
Integers
的编码格式如下:
-
第一个字符为 :
-
紧接着为不能包含 CR
或LF
的数字 -
以 CRLF
结尾
在Redis
中,当需要返回整型的时候,就是用的Integers
进行返回,如INCR
、LLEN
等命令,比如执行incr a
命令,返回如下
:1rn
Bluk Strings
Bluk Strings
用于表示二进制安全的字符串,最大能存储 512M 的数据,Bluk Strings
的编码格式如下:
-
第一个字节为 $
-
紧接着一个数字用于表示字符串的字节数(称为 prefixed length
,也就是前缀长度),前缀长度以CRLF
结尾 -
接着为真实的字符串数据 -
以 CRLF
结尾
比如字符串foobar
使用Bluk Strings
编码为
$3rnfoobarrn
空字符串(对应java
中的""
)表示为
$0rnrn
特别注意的是,RESP
使用长度为-1
的Bluk Strings
表示不存在的值,即NULL
$-1rn
各客户端在解析的时候,需要转换为对应语言的NULL
值,如Ruby
中的nil
,C
中的NULL
等
数组 Arrays
当服务端需要返回多个数据给客户端的时候,就是使用Arrays
进行返回的,如LRANGE
命令返回的就是一个数组。此外,客户端发送给服务端的命令,也都是使用Arrays
进行发送的。Arrays
的编码格式如下:
-
第一个字符为 *
-
后面接数组的元素个数,以 CRLF
结尾 -
接着为 Arrays
中每个元素的数据,元素类型为上面介绍的4
种数据类型
比如空数组可以表示为
*0rn
包含两个Bluk Strings
元素,元素内容分别为foo
跟bar
的Arrays
表示为
*2rn$3rnfoorn$3rnbarrn
Arrays
中各个元素的数据类型可以不同,比如包含一个Integer
类型跟一个Simple Strings
类型的Arrays
,表示为
*2rn:1rn+hellorn
客户端发送命令也是使用Arrays
进行发送的,下面同样通过nc
举例,比如发送SET foo bar
命令
$ echo -e '*3rn$3rnsetrn$3rnfoorn$3rnbarrn' | nc localhost 6379
+OK
内联命令
Redis
提供了内联命令,方便我们在没有redis-cli
的时候,使用telnet
等其他工具与redis
进行交互
-
使用 telnet
与 redis-server 交互
$ telnet localhost 6379
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
PING
+PONG
SET foo bar
+OK
-
使用 Netcat
与 redis-server 进行交互
$ nc localhost 6379
PING
+PONG
SET foo bar
+OK
总结
可以看到,RESP
协议设计非常简单,用前缀区分不同的数据类型,相比 JSON/XML,RESP 的数据类型更加紧凑,传输效率更高,这也是 redis 为什么这么快的原因之一
了解RESP
,如果你需要写一款 Redis 客户端或者小工具,就知道怎么与 redis 进行交互啦,而且多了解不同系统的协议设计,可以开拓我们的思路,以后遇到需要自己设计协议的时候,可以作为参考
原文始发于微信公众号(huangxy):一文搞懂 Redis 通讯协议 RESP
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/160054.html