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

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

你好,我是蒋德钧。
在前面的课程中,我们主要学习了 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 核心技术与实战》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(13)

  • 最新
  • 精选
  • 杨逸林
    语音中有一个和文本内容不符合的地方,就是那个“正常的 0 字符”。语音是正常的空字符,文本就是前面引号的部分,是哪个对的呢,还是都对的?

    作者回复: '\0'对应的ASCII码值就是0,所以我称为了0字符。同时,'\0'也是转义字符,表示空字符,所以语音中直接说成了空字符。在咱们这篇文章中,都是对的。 造成了困扰,不好意思啊!

    2
    10
  • 谢小路
    RESP 也可以通过抓包的方式来具体查看格式,使用 tcpdump 进行抓包得到的文件,使用 wireshark 进行查看,也比较直观。

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

    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>。 如果我们在设计一个通信协议时,可以作为参考,根据自己的场景进行选择。
    3
    119
  • 悟空聊架构
    文中最后的小结完美总结了本篇的主要内容。这篇可以先看小结内容,然后再通读全文,这样整体脉络会比较清晰。 另外文中的一张总结图很棒,一图胜千言。
    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 ```
    1
  • 约书亚
    用旧的客户端连接6没看到返回合适有变化,2和3的兼容是服务端做的嘛?
    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
    归属地:江苏
  • 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
    归属地:江苏
  • Geek_LIAO
    字符串长度达到多长时不使用简单字符串类型,而使用长字符串类型进行编码呢?
    归属地:江苏
  • NULL
    Redis Serialization Protocol (RESP) Specifications https://github.com/redis/redis-specifications/tree/master/protocol
    归属地:山东
收起评论
显示
设置
留言
13
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部