设计网站会员哪个好用,python 网站开发 linux,网站推广seo系统,wordpress开启mu简述
Redis 使用 RESP 协议#xff08;Redis Serialzation Protocol#xff09;协议定义了客户端和服务器端交互的命令、数据的编码格式。在 Redis 2.0 版本中#xff0c;RESP 协议正式称为客户端和服务器端的标准通信协议。从 Redis 2.0 到 Redis 5.0 #xff0c;RESP 协…简述
Redis 使用 RESP 协议Redis Serialzation Protocol协议定义了客户端和服务器端交互的命令、数据的编码格式。在 Redis 2.0 版本中RESP 协议正式称为客户端和服务器端的标准通信协议。从 Redis 2.0 到 Redis 5.0 RESP 协议都称为 RESP 2 协议从 Redis 6.0 开始Redis 就采用 RESP 3 协议了。 1.客户端和服务器端交互的内容有哪些
RESP 2 协议是如何对命令和数据进行格式编码的呢
我们可以把交互内容分成客户端请求和服务器端响应两类
在客户端请求中客户端会给 Redis 发送命令以及要写入的键和值。而在服务器响应中Redis 实例会返回 读取的值OK 标识成功写入的元素个数错误信息以及命令如 Redis Cluster 中的 MOVE 命令
其实这些交互内容还可以再进一步细分成 7 类
命令这就是针对不同数据类型的命令操作。例如对 String 类型的 SET、GET 操作对 Hash 类型的 HSET、HGET 等这些命令就是代表操作语义的字符串。键键值对中的键可以直接用字符串表示。单个值对应 String 类型的数据数据本身可以是字符串、数值整数或浮点数布尔值True 或 False等。集合值对应 List、Hash、Set、Sorted Set 类型的数据不仅包含多个值而且每个值也可以是字符串、数值或布尔值等。OK 回复对应命令操作成功的结果就是一个字符串的 OK。整数回复这里有两种情况。 一种是命令操作返回的结果是整数例如 LLEN 命令返回列表的长度。另一种是集合命令成功操作时实际操作元素的个数例如 SADD 命令返回成功添加的元素个数。 错误信息命令操作出错是的返回结果包括 error 标识以及具体的错误信息。
下面再接个三个具体的例子帮助你进一步掌握这些交互内容。
第一个例子
# 成功写入String类型数据返回 OK
127.0.0.1:6379 SET testkey testvalue
OK这里的交互内容就包括了命令SET 命令、键String类型的键 testkey和单个值String 类型的 testvalue而服务器端直接返回一个 OK 回复。
第二个例子
# 成功写入Hash类型数据返回实际写入的集合元素个数
127.0.0.1:6379 HSET testhash a 1 b 2 c 3
(integer) 3这里的交互内容包括三个 key-value 的 Hash 集合值a 1 b 2 c 3而服务器端返回整数回复3表示成功写入的元素个数。
第三个例子
# 发送的命令不对报错并返回报错信息
127.0.0.1:6379 PUT testkey2 testvalue
(error) ERR unknown command PUT, with args beginning with: testkey2, testvalue这里的交互内容包括三个 key-value 的 Hash 集合值a 1 b 2 c 3而服务器端返回整数回复3表示成功写入的元素个数。
可以看到这里的交互内容包括错误信息这是因为Redis 实例本身不支持 PUT 命令所以服务器报错 error 并返回具体的报错也就是位置的命令 “PUT”。
2.RESP 2的编码格式规范
RESP 2 协议的设计目标是希望 Redis 开发人员实现客户端时简单方便这样可以减少客户端开发时出现的 Bug。而且客户端和服务器端交互出现问题时开发人员可以通过查看协议交互过程能快速定位问题方便调试。所以RESP 2 协议采用了可读性很好的文本形式进行编码也就是通过字符串来表示各种命令和数据。
不过交互内容有多重而且实际传输的命令或数据也会有多个。针对这两种情况RESP 2 协议在编码时设计了两个基本规范。
为了对不同类型的交互内容进行编码RESP 2 协议实现了物资编码格式类型。同时为了区分这 5 种编码类型RESP 2 使用一个专门的字符作为每种编码类型的开头字符。这样客户端或服务器端进行解析时可以直接通过开头字符串知道当前解析的编码类型。RESP 2 进行编码时会按照单个命令或单个数据的粒度进行编码并在每个编码结果后增加一个换行符 \r\n有时也表示成 CRLF表示一次编码结束。
接下来分别结束下这 5 中编码类型。
2.1 简单字符串类型RESP Simple String
这种类型就是用一个字符串来进行编码比如请求操作在服务器端成功执行后的 OK 表示回复就是这种类型进行编码的
当服务器端成功执行一个操作后返回的 OK 标识就可以编码如下
OK\r\n2.2 长字符串类型RESP Bulk String
这种类型是用一个二进制安全的字符串来进行编码。
这里的二进制安全是相对于 C 语言中对字符串的处理方式来说的。 Redis 在解析字符串时不会像 C 语言那样使用 \0 来判定一个字符串的结尾Redis 会把 \0 解析成正常的 0 字符并使用额外的属性值表示字符串的长度。
对于 Redis\0Cluster\0 这个字符串来说C 语言会解析为 “Redis”而 Redis 会解析为 “Redis Cluster”并用 len 属性字符串的真实长度是 14 字节如下图所示 这样一来字符串中即使存储了 \0 字符也不会导致 Redis 解析到 \0 时就认为字符串结束了从而停止这就保证了数据的安全性。和长字符串类相比简单字符串就是非二进制安全的。
长字符串类型最大可以达到 512 MB所以可以对很大的数据量进行编码正好可以满足键值对本身的数据量需求所以 RESP 2 就用这种类型对交互内容中的键或值进行编码并且使用 $ 字符作为开头字符 $ 字符后面会紧跟一个数字这个数字表示字符串的实际长度。
例如我们使用 GET 命令读取一个键假设为 testkey的值假设值为 testvalue时服务器端返回的 String 值编码如下其中 $ 字符后的 9 表示数据长度为 9 个字符。
$9 testvalue\r\n2.3 整数类型RESP Integer
这种数据类型也是一个字符串但表示的是一个有符号 64 位整数。为了和包含数字的简答字符串类型区分开整数类型使用 : 字符作为开头可以用于对服务器端返回的整数回复进行编码。
例如上面的第二个例子中我们使用 HSET 命令设置了 testhash 的三个元素服务器端实际返回的编码结果如下
:3\r\n2.4 错误类型RESP Errors
它是一个字符串包括了错误类型和具体的错误信息。Redis 服务器端报错响应就是用这种类型进行编码的。RESP 2 使用 - 字符作为它的开头字符。
例如上面的第三个例子中我们在 redis-cli 执行 PUT testkey2 testvalue 命令报错服务器端实际返回给客户端的报错编码结果如下
-ERR unknown command PUT, with args beginning with: testkey2, testvalue其中 ERR 就是报错类型表示一个统一错误ERR 后面的文字内容就是具体的报错信息。
2.5 数组编码类型RESP Arrays
这是一个包含多个元素的数组之前元素的类型可以是刚刚介绍的 4 种编码类型。
在客户端发送请求和服务器端返回结果时数组编码类型都能用的上。客户端在发送请求操作时一般会同时包括命令和要操作的数据。而数组类型包含了多个元素所以就适合用来对发送的命令和数据进行编码。为了和其他类型区分开RESP 2 使用 * 字符作为它的开头字符。
例如我们执行 GET testkey此时客户端发送给服务器端的命令的编码结果就是使用数组类型编码的如下所示
*2\r\n$3\r\nGET\r\n$7\r\ntestkey\r\n其中第一个 * 字符标识当前是数组类型的编码结果2 标识该数组有 2 个元素分别对应命令 GET 和 键 testkey。命令 GET 和 键 testkey都是使用长字符串类型编码的所以用 $ 字符加字符串长度来表示。
类型的当服务器端返回包含多个元素的集合类型数据时也会用 * 字符和元素个数作为标识并用长字符串类型对返回的集合元素进行编码。
RESP 2 协议的 5 种编码类型和相应的开头字符我在下表做了小结。
编码类型简单字符串长字符串整数错误数组开头第一个字符$:-*
3.RESP 2 的不足和 RESP 3 的改进
虽然 RESP 2 协议提供了 5 种编码类型看起来很丰富其实是不够的。比较基本数据类型还包括很多例如浮点数、布尔值等。编码类型偏少会带来两个问题。
一方面在值的基本数据类型方面RESP 2 只能区分字符串和证书对于其他的数据类型客户端使用 RESP 2 协议时就需要进行额外的转换操作。例如当一个浮点数用字符串表示时客户端需要将字符串中的值和实际数字值比较判断是否为数字值然后再将字符串转换成实际的浮点数。另一方面RESP 2 用数组类别编码表示所有的集合类型但是Redis 的集合类型包括了 List、Hash、Set 和 Sorted Set。当客户端接收到数组类型编码的结果时还需要根据 调用的命令操作接口来判断返回的数组究竟是哪一种集合类型。
假设一个 Hash 类型的键是 testhash集合元素分别为 a:1、b:2、c:3。同时有一个 Sorted Set 类型的键 testzset集合的元素分别是 a、b、c它们的分数分别是 1、2、3.我们在 redis-cli 客户端中读取它们返回的结果时返回的形式都是一个数组
127.0.0.1:6379 HGETALL testhash
1) a
2) 1
3) b
4) 2
5) c
6) 3127.0.0.1:6379 ZRANGE testzset 0 3 withscores
1) a
2) 1
3) b
4) 2
5) c
6) 3为了在客户端按照 Hash 和 Sorted Set 两种类型处理代码中返回的数据客户端还需要根据发送的命令操作 HGETALL 和 ZRANGE 来把这两个编码的数组结果转换成相应的 Hash 集合和有序集合增加了客户端额外的开销。
从 Redis 6.0 版本开始RESP 3 协议增加了对多种数据类型的支持包括
空值浮点数布尔值有序的字典集合无需的集合等
RESP 3 也是通过不同的开头字符区分不同的数据类型例如当开头第一个字符是 ,就表示接下来的结果是浮点数。这样一来客户端就不用再通过额外的字符串对比来实现数据转换操作了提升了客户端的效率。
4.小结
RESP 2 协议题了 5 中类型的编码格式包括简单字符串类型、长字符串类型、整数类型、错误类型和数组类型。为了区分这 5 种类型RESP 2 协议使用了 5 种不同的开头字符作为这 5 种类型编码结果的第一个字符分别是 、$、:、-、*。
RESP 2 协议是文本形式的协议实现简单可以减少客户端开发出现的 Bug而且可读性强便于开发调试。当你需要定制化 Redis 客户端时就需要了解和掌握 RESP 2 协议。
RESP 2 协议的一个不足就是支持的类型偏少所以 Redis 6.0 版本使用了 RESP 3 协议。和 RESP 2 协议相比RESP 3 协议增加了对浮点数、布尔类型、有序字典集合、无序集合等多种类型数据的支持。不过这里有个地方需要你注意Redis 6.0 只支持 RESP 3对 RESP 2 协议不兼容所以如果你使用 Redis 6.0 版本需要确认客户端已经支持了 RESP 3 协议否则将无法使用 Redis 6.0。
如果你想查看服务器端返回数据的 RESP 2 编码结果就可以使用 telnet 命令和 Redis 实例连接执行如下命令
telnet 实例IP 实例端口接着给实例发送命令这样就能看到 RESP 2 协议编码后的返回结果了。当然你也可以在 telnet 中想 Redis 实例发送 RESP 2 协议编写的命令实例同样能处理。