我们之前说了Redis服务器端的机制和关键技术,很少涉及到客户端的问题,但是Redis采用的是典型的client-server架构,客户端发起请求,服务器端返回相应给客户端

而其中Client和Server的交互,利用的是Redis自定义的RESP协议

早期版本是RESP 2协议,从6.0开始,使用RESP3 协议了,关于两者的区别,就是我们本章的说明重点

首先是RESP 2协议

如何对命令和数据进行格式编码的,分为客户端请求和服务器端响应流程

客户端会在给Redis发送命令的时候,带上要写入的键和值

服务器端响应的时候,Redis会读取返回的值,OK的标识,写入的元素个数,错误信息,以及命令

RESP2 将这些命令分为7类,分别是

命令:不同数据类型的操作命令,String类型的SET GET HSET HGET等

键:键值对中的键,用字符串表示

单个值:对应String类型的数据,数据本身可以是字符串 数值,布尔值

集合值:对应List Hash Set Sorted Set类型的数据,包含多个值

OK回复

整数回复

错误信息

根据这些返回类型,我们看下RESP2 的实现方式

RESP 2协议的目标是,希望Redis实现客户端更加方便,可以减少客户端开发时候出现的bug,所以直接使用可读性的文本形式进行编码

并且将上面命令分为了5种编码格式类型,区分这5种编码类型,RESP2 使用一个专门的字符串,表示每种编码类型的开头字符,这样,客户端或者服务器端在编码后的数据进行解析的时候,可以通过开头字符知道当前解析的编码类型

RESP在编码之后,根据单个命令或者单个数据的粒度进行编码,并且在每个编码的结果后面增加一个换行符 “\r\n”,表示编码的结束

RESP2的第一种编码格式

简单字符串类型

就是一个字符串进行编码前面用一个+表示是字符串,比如下面的编码格式

+OK\r\n

长字符串类型

对于长字符串类型,RESP2在前面使用$作为开头字符串,后面跟着一个数字表示字符串的实际长度

假设如下我们使用GET命令读取一个键,返回的String类型就会如下

$9 testvalue\r\n

整数类型

整数类型以 “:”字符作为开头字符,可以用于对服务端返回的整数回复进行编码

:3\r\n

错误类型

是一个字符串,包含了错误类型和具体的错误信息,RESP2使用 – 字符作为其开头字符

我们使用redis-cli执行PUT testkey testvalue的话

会得到一个ERROR信息,结果如下

-ERR unknown command

数组类型

一个包含多个元素的数组,元素类型可以是刚刚说的4种编码类型

客户端发送请求和服务器端返回结果的时候,数组类型都能用得上,其开头为 “*”字符

数据类型如下

*2\r\n$3\r\nGET\r\n$7\r\ntestkey\r\n

整体总结如下

图片

虽然RESP 2提供了5种编码类型,但是在Redis中,还有很多额外的基本数据类型,比如浮点数,布尔值等

另一方面,RESP2只能区分字符串和整数,对于其他的数据类型,需要由客户端进行额外的转换操作,当需要一个浮点数的时候,就需要比较返回的字符串,是否可以转换为浮点数

而且RESP2使用数组表示所有的集合类型,但是集合包含了List Hash Set Sorted Set,当收到数组类型编码的时候,还需要判断是哪种集合类型

就好比,我们有两个集合操作,分别是HGETALL testhash 和 ZRANGE testzset 0 3 withscores

获取结果都是如下

127.0.0.1:6379>HGETALL testhash

1) “a”

2) “1”

3) “b”

4) “2”

5) “c”

6) “3”

127.0.0.1:6379>ZRANGE testzset 0 3 withscores

1) “a”

2) “1”

3) “b”

4) “2”

5) “c”

6) “3”

那么就需要客户端根据这两者的请求命令操作,转换为对应的Hash和有序集合,增加了客户端额外的开销

而RESP3则是增加了多种数据类型的支持,包含空值,浮点数,布尔值,有序的字典集合,无序的集合等

这样客户端就不需要进行额外的命令获取比较了,提升了客户端的效率

总结一下这一节,我们说了RESP这个Redis自定义的通信协议,定义了Redis客户端和服务器端进行交互的格式,RESP2是之前版本的通信协议,定义了基本的5种编码格式,包含了字符串 长字符串,整数,错误类型,数组类型,每种类型都有自己独特的编码字符表示

不过RESP2的支持类型还是太少,于是Redis 6.0支持了RESP3协议,增加了对浮点数,布尔类型 有序字典集合,无序集合等多种类型的支持,但因为两者协议不兼容,对于协议不兼容需要注意

最后一个小问题,假如Redis实例中由一个List类型的数据,key为mylist,value为LPUSH命令写入List集合的5个元素,分别是1,2,3.3,4,hello,执行LRANGE mylist 0 4 命令的时候,返回给客户端的编码结果是怎么样的

应该如下

Trying 127.0.0.1…

Connected to localhost.

Escape character is ‘^]’.

LRANGE mylist 0 4

*5

$5

hello

$1

4

$3

3.3

$1

2

$1

1

换行符已经交由命令行工具自动解析到了

发表评论

邮箱地址不会被公开。 必填项已用*标注