一文搞懂 Redis 通讯协议 RESP

什么是 RESP

RESPREdis 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 StringsErrorsIntergersBulk StringsArrays,第一个字节与数据类型的映射关系如下:

  • Simple Strings类型,第一个字节为+
  • Errors类型,第一个字节为-
  • Integers类型,第一个字节为:
  • Bulk Strings类型,第一个字节为$
  • Arrays类型,第一个字节为*

下面分别介绍这几种数据类型

简单字符串 Simple Strings

Simple Strings是 Redis 中比较常见的数据类型,很多的响应用的都是Simple Strings类型,的编码方式如下:

  • 第一个字符为+
  • 紧接着是一个不能包含CRLF的字符串(不允许换行)
  • CRLF结束

Simple Strings能保证在最小开销的情况下传输非二进制安全的字符串,比如很多Redis命令执行成功都要返回OK字符串,该字符串通过Simple Strings编码为5个字节的数据报如下

+OKrn

错误响应 Errors

Errors用于返回异常信息,当 redis 命令执行错误的时候,就会返回Errors类型的响应。Errors的编码方式如下:

  • 第一个字符为-
  • 紧接着是一个不能包含CRLF的字符串(不允许换行)
  • CRLF结束

可以看到,Errors的编码方式和Simple Strings很像,唯一的区别是Errors的第一个字符是-,下面是一个Errors响应的例子

-ERR value is not an integer or out of rangern

整型 Integers

Integers的编码格式如下:

  • 第一个字符为:
  • 紧接着为不能包含CRLF的数字
  • CRLF结尾

Redis中,当需要返回整型的时候,就是用的Integers进行返回,如INCRLLEN等命令,比如执行incr a命令,返回如下

:1rn

Bluk Strings

Bluk Strings用于表示二进制安全的字符串,最大能存储 512M 的数据,Bluk Strings的编码格式如下:

  • 第一个字节为$
  • 紧接着一个数字用于表示字符串的字节数(称为prefixed length,也就是前缀长度),前缀长度以CRLF结尾
  • 接着为真实的字符串数据
  • CRLF结尾

比如字符串foobar使用Bluk Strings编码为

$3rnfoobarrn

空字符串(对应java中的"")表示为

$0rnrn

特别注意的是,RESP使用长度为-1Bluk Strings表示不存在的值,即NULL

$-1rn

各客户端在解析的时候,需要转换为对应语言的NULL值,如Ruby中的nilC中的NULL

数组 Arrays

当服务端需要返回多个数据给客户端的时候,就是使用Arrays进行返回的,如LRANGE命令返回的就是一个数组。此外,客户端发送给服务端的命令,也都是使用Arrays进行发送的。Arrays的编码格式如下:

  • 第一个字符为*
  • 后面接数组的元素个数,以CRLF结尾
  • 接着为Arrays中每个元素的数据,元素类型为上面介绍的4种数据类型

比如空数组可以表示为

*0rn

包含两个Bluk Strings元素,元素内容分别为foobarArrays表示为

*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

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!