加餐(四) | Redis客户端如何与服务器端交换命令和数据?
该思维导图由 AI 生成,仅供参考
- 深入了解
- 翻译
- 解释
- 总结
Redis 通信协议:从 RESP 2 到 RESP 3 Redis通信协议RESP(REdis Serialization Protocol)是Redis客户端与服务器端通信的标准协议。RESP 2协议采用文本形式进行编码,包括简单字符串、长字符串、整数、错误和数组编码类型。然而,RESP 2协议在处理基本数据类型和集合类型时存在不足,需要客户端进行额外的转换操作。为解决这一问题,Redis 6.0引入了RESP 3协议,对多种数据类型提供支持,包括空值、浮点数、布尔值等,通过不同的开头字符来区分不同的数据类型,提升了客户端的效率。RESP 3协议的改进使得客户端无需进行额外的转换操作,从而更好地满足Redis客户端二次开发或对Redis通信协议有兴趣的读者的需求。 RESP 2协议提供了5种类型的编码格式,包括简单字符串类型、长字符串类型、整数类型、错误类型和数组类型。 RESP 2协议是文本形式的协议,实现简单,可读性强,便于开发调试。然而,RESP 2协议支持的类型偏少,因此Redis 6.0版本使用了RESP 3协议,增加了对浮点数、布尔类型、有序字典集合、无序集合等多种类型数据的支持。需要注意的是,Redis 6.0只支持RESP 3,对RESP 2协议不兼容。 如果读者想查看服务器端返回数据的RESP 2编码结果,可以使用telnet命令和redis实例连接,执行相应命令。此外,读者也可以在telnet中,向Redis实例发送用RESP 2协议编写的命令操作,实例同样能处理。 总之,RESP 3协议的引入为Redis客户端开发带来了便利,消除了RESP 2协议的不足之处,使得客户端无需进行额外的转换操作。这对于二次开发或对Redis通信协议有兴趣的读者来说,是一次重要的改进。
《Redis 核心技术与实战》,新⼈⾸单¥68
全部留言(13)
- 最新
- 精选
- 杨逸林语音中有一个和文本内容不符合的地方,就是那个“正常的 0 字符”。语音是正常的空字符,文本就是前面引号的部分,是哪个对的呢,还是都对的?
作者回复: '\0'对应的ASCII码值就是0,所以我称为了0字符。同时,'\0'也是转义字符,表示空字符,所以语音中直接说成了空字符。在咱们这篇文章中,都是对的。 造成了困扰,不好意思啊!
2020-10-25210 - 谢小路RESP 也可以通过抓包的方式来具体查看格式,使用 tcpdump 进行抓包得到的文件,使用 wireshark 进行查看,也比较直观。
作者回复: tcpdump和wireshark是两个不错的工具!
2020-11-192 - Kaitokey为mylist,使用LPUSH写入是1、2、3.3、4、hello,执行LRANGE mylist 0 4命令时,实例返回给客户端的编码结果是怎样的? 测试结果如下,写入命令: 127.0.0.1:6479> LPUSH mylist 1 2 3.3 4 hello (integer) 5 127.0.0.1:6479> LRANGE mylist 0 4 1) "hello" 2) "4" 3) "3.3" 4) "2" 5) "1" 使用telnet发送命令,观察结果: 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 Redis设计的RESP 2协议非常简单、易读,优点是对于客户端的开发和生态建设非常友好。但缺点是纯文本,其中还包含很多冗余的回车换行符,相比于二进制协议,这会造成流量的浪费。但作者依旧这么做的原因是Redis是内存数据库,操作逻辑都在内存中进行,速度非常快,性能瓶颈不在于网络流量上,所以设计放在了更加简单、易理解、易实现的层面上。 Redis 6.0重新设计RESP 3,比较重要的原因就是RESP 2的语义能力不足,例如LRANGE/SMEMBERS/HGETALL都返回一个数组,客户端需要根据发送的命令类型,解析响应再封装成合适的对象供业务使用。而RESP 3在响应中就可以明确标识出数组、集合、哈希表,无需再做转换。另外RESP 2没有布尔类型和浮点类型,例如EXISTS返回的是0或1,Sorted Set中返回的score是字符串,这些都需要客户端自己转换处理。而RESP 3增加了布尔、浮点类型,客户端直接可以拿到明确的类型。 另外,由于TCP协议是面向数据流的,在使用时如何对协议进行解析和拆分,也是分为不同方法的。常见的方式有4种: 1、固定长度拆分:发送方以固定长度进行发送,接收方按固定长度截取拆分。例如发送方每次发送数据都是5个字节的长度,接收方每次都按5个字节拆分截取数据内容。 2、特殊字符拆分:发送方在消息尾部设置一个特殊字符,接收方遇到这个特殊字符就做拆分处理。HTTP协议就是这么做的,以\r\n为分隔符解析协议。 3、长度+消息拆分:发送方在每个消息最前面加一个长度字段,接收方先读取到长度字段,再向后读取指定长度即是数据内容。Redis采用的就是这种。 4、消息本身包含格式:发送方在消息中就设置了开始和结束标识,接收方根据这个标识截取出中间的数据。例如<start>msg data<end>。 如果我们在设计一个通信协议时,可以作为参考,根据自己的场景进行选择。2020-10-233122
- 悟空聊架构文中最后的小结完美总结了本篇的主要内容。这篇可以先看小结内容,然后再通读全文,这样整体脉络会比较清晰。 另外文中的一张总结图很棒,一图胜千言。2021-05-303
- escray在 macOS 上默认似乎是没有 telnet 的,放狗搜索,似乎是可以安装一个 telnet,也可以使用 ssh 或者 nc 工具。 我尝试使用 ssh 被拒绝了,然后使用 nc 连上了阿里云的 Redis 实例。 ``` #> nc -v r-2zede1d2b3b2b312pd.redis.rds.aliyuncs.com 6379 Connection to r-2zede0d1b1b2b564pd.redis.rds.aliyuncs.com port 6379 [tcp/*] succeeded! ``` 连接之后,是没有命令提示符的。直接 hello world,需要输入密码 ``` get hello -NOAUTH Authentication required. auth myPassword +OK get hello $5 world ``` 然后看一下专栏中提到的例子 ``` LRANGE mylist 0 4 *5 $5 hello $1 4 $3 3.3 $1 2 $1 1 set testkey testvalue +OK get testkey $9 testvalue hset testhash a 1 b 2 c 3 :3 put testkey2 testvalue -ERR unknown command `put`, with args beginning with: `testkey2`, `testvalue`, ``` 可以看到 mylist 中的值都是使用长字符串类型(RESP Bulk String)来回复的,还能看到 以“:”开头的简单字符串类型(RESP Simple Strings),用“+”号开头的整数类型(RESP Integer)和用“-”号开头的错误类型(RESP Errors) 用“*”号开头的数组编码类型(RESP Arrays)没有看到具体的例子。 最后,关于 Hash 类型的 testhash 和 Sorted Set 类型的 testzset 的例子 ``` hset testhash a 1 b 2 c 3 :0 hgetall testhash *6 $1 a $1 1 $1 b $1 2 $1 c $1 3 zadd testzset 1 "a" :1 zadd testzset 2 "b" :1 zadd testzset 3 "c" :1 zrange testzset 0 3 withscores *6 $1 a $1 1 $1 b $1 2 $1 c $1 3 ```2021-03-221
- 约书亚用旧的客户端连接6没看到返回合适有变化,2和3的兼容是服务端做的嘛?2021-02-051
- Geek_LIAOlpush mylist 1 2 3.3 4 hello :5 lrange mylist 0 4 *5 $5 hello $1 4 $3 3.3 $1 2 $1 12023-02-18归属地:江苏
- Geek_LIAO在 telnet 中,向 Redis 实例发送用 RESP 2 协议编写的命令操作,为什么报错? *2\r\n$3\r\nGET\r\n$7\r\ntestkey\r\n -ERR Protocol error: invalid multibulk length2023-02-18归属地:江苏
- Geek_LIAO字符串长度达到多长时不使用简单字符串类型,而使用长字符串类型进行编码呢?2023-02-18归属地:江苏
- NULLRedis Serialization Protocol (RESP) Specifications https://github.com/redis/redis-specifications/tree/master/protocol2022-09-10归属地:山东