Redis 核心技术与实战
蒋德钧
中科院计算所副研究员
81696 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 53 讲
开篇词 (1讲)
实践篇 (28讲)
Redis 核心技术与实战
15
15
1.0x
00:00/00:00
登录|注册

加餐(四) | Redis客户端如何与服务器端交换命令和数据?

RESP 3协议
RESP Arrays
RESP Errors
RESP Integer
RESP Bulk String
RESP Simple Strings
错误信息
整数回复
OK回复
集合值
单个值
命令
每课一问
RESP 2的不足和RESP 3的改进
RESP 2的编码格式规范
客户端和服务器端交互的内容
RESP 2协议
Redis客户端如何与服务器端交换命令和数据?
参考文章

该思维导图由 AI 生成,仅供参考

你好,我是蒋德钧。
在前面的课程中,我们主要学习了 Redis 服务器端的机制和关键技术,很少涉及到客户端的问题。但是,Redis 采用的是典型的 client-server(服务器端 - 客户端)架构,客户端会发送请求给服务器端,服务器端会返回响应给客户端。
如果要对 Redis 客户端进行二次开发(比如增加新的命令),我们就需要了解请求和响应涉及的命令、数据在客户端和服务器之间传输时,是如何编码的。否则,我们在客户端新增的命令就无法被服务器端识别和处理。
Redis 使用 RESP(REdis Serialization Protocol)协议定义了客户端和服务器端交互的命令、数据的编码格式。在 Redis 2.0 版本中,RESP 协议正式成为客户端和服务器端的标准通信协议。从 Redis 2.0 到 Redis 5.0,RESP 协议都称为 RESP 2 协议,从 Redis 6.0 开始,Redis 就采用 RESP 3 协议了。不过,6.0 版本是在今年 5 月刚推出的,所以,目前我们广泛使用的还是 RESP 2 协议。
这节课,我就向你重点介绍下 RESP 2 协议的规范要求,以及 RESP 3 相对 RESP 2 的改进之处。
首先,我们先来看下客户端和服务器端交互的内容包括哪些,毕竟,交互内容不同,编码形式也不一样。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
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-25
    2
    10
  • 谢小路
    RESP 也可以通过抓包的方式来具体查看格式,使用 tcpdump 进行抓包得到的文件,使用 wireshark 进行查看,也比较直观。

    作者回复: tcpdump和wireshark是两个不错的工具!

    2020-11-19
    2
  • Kaito
    key为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-23
    3
    122
  • 悟空聊架构
    文中最后的小结完美总结了本篇的主要内容。这篇可以先看小结内容,然后再通读全文,这样整体脉络会比较清晰。 另外文中的一张总结图很棒,一图胜千言。
    2021-05-30
    3
  • 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-22
    1
  • 约书亚
    用旧的客户端连接6没看到返回合适有变化,2和3的兼容是服务端做的嘛?
    2021-02-05
    1
  • Geek_LIAO
    lpush mylist 1 2 3.3 4 hello :5   lrange mylist 0 4 *5 $5 hello $1 4 $3 3.3 $1 2 $1 1
    2023-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 length
    2023-02-18归属地:江苏
  • Geek_LIAO
    字符串长度达到多长时不使用简单字符串类型,而使用长字符串类型进行编码呢?
    2023-02-18归属地:江苏
  • NULL
    Redis Serialization Protocol (RESP) Specifications https://github.com/redis/redis-specifications/tree/master/protocol
    2022-09-10归属地:山东
收起评论
显示
设置
留言
13
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部