Redis 核心技术与实战
蒋德钧
中科院计算所副研究员
25213 人已学习
立即订阅
登录后,你可以任选4讲全文学习
推荐试读
换一换
02 | 数据结构:快速的Redis有哪些慢操作?
04 | AOF日志:宕机了,Redis如何避免数据丢失?
17 | 为什么CPU结构也会影响Redis的性能?
课程目录
已完结/共 53 讲
开篇词 (1讲)
开篇词 | 这样学Redis,才能技高一筹
基础篇 (10讲)
01 | 基本架构:一个键值数据库包含什么?
02 | 数据结构:快速的Redis有哪些慢操作?
03 | 高性能IO模型:为什么单线程Redis能那么快?
04 | AOF日志:宕机了,Redis如何避免数据丢失?
05 | 内存快照:宕机后,Redis如何实现快速恢复?
06 | 数据同步:主从库如何实现数据一致?
07 | 哨兵机制:主库挂了,如何不间断服务?
08 | 哨兵集群:哨兵挂了,主从库还能切换吗?
09 | 切片集群:数据增多了,是该加内存还是加实例?
10 | 第1~9讲课后思考题答案及常见问题答疑
实践篇 (28讲)
11 | “万金油”的String,为什么不好用了?
12 | 有一亿个keys要统计,应该用哪种集合?
13 | GEO是什么?还可以定义新的数据类型吗?
14 | 如何在Redis中保存时间序列数据?
15 | 消息队列的考验:Redis有哪些解决方案?
16 | 异步机制:如何避免单线程模型的阻塞?
17 | 为什么CPU结构也会影响Redis的性能?
18 | 波动的响应延迟:如何应对变慢的Redis?(上)
19 | 波动的响应延迟:如何应对变慢的Redis?(下)
20 | 删除数据后,为什么内存占用率还是很高?
21 | 缓冲区:一个可能引发“惨案”的地方
22 | 第11~21讲课后思考题答案及常见问题答疑
23 | 旁路缓存:Redis是如何工作的?
24 | 替换策略:缓存满了怎么办?
25 | 缓存异常(上):如何解决缓存和数据库的数据不一致问题?
26 | 缓存异常(下):如何解决缓存雪崩、击穿、穿透难题?
27 | 缓存被污染了,该怎么办?
28 | Pika:如何基于SSD实现大容量Redis?
29 | 无锁的原子操作:Redis如何应对并发访问?
30 | 如何使用Redis实现分布式锁?
31 | 事务机制:Redis能实现ACID属性吗?
32 | Redis主从同步与故障切换,有哪些坑?
33 | 脑裂:一次奇怪的数据丢失
34 | 第23~33讲课后思考题答案及常见问题答疑
35 | Codis VS Redis Cluster:我该选择哪一个集群方案?
36 | Redis支撑秒杀场景的关键技术和实践都有哪些?
37 | 数据分布优化:如何应对数据倾斜?
38 | 通信开销:限制Redis Cluster规模的关键因素
期中测试 (2讲)
期中测试题 | 一套习题,测出你的掌握程度
期中测试题答案 | 这些问题,你都答对了吗?
未来篇 (3讲)
39 | Redis 6.0的新特性:多线程、客户端缓存与安全
40 | Redis的下一步:基于NVM内存的实践
41 | 第35~40讲课后思考题答案及常见问题答疑
加餐篇 (7讲)
加餐(一)| 经典的Redis学习资料有哪些?
加餐(二)| 用户Kaito:我是如何学习Redis的?
加餐(三)| 用户Kaito:我希望成为在压力中成长的人
加餐(四) | Redis客户端如何与服务器端交换命令和数据?
加餐(五) | Redis有哪些好用的运维工具?
加餐(六)| Redis的使用规范小建议
加餐(七) | 从微博的Redis实践中,我们可以学到哪些经验?
结束语 (2讲)
期末测试 | 这些Redis核心知识,你都掌握了吗?
结束语 | 从学习Redis到向Redis学习
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/1000字
划线
笔记
复制
02 | 数据结构:快速的Redis有哪些慢操作?
04 | AOF日志:宕机了,Redis如何避免数据丢失?
17 | 为什么CPU结构也会影响Redis的性能?
24 | 替换策略:缓存满了怎么办?
40 | Redis的下一步:基于NVM内存的实践
加餐(七) | 从微博的Redis实践中,我们可以学到哪些经验?
开通超级会员免费畅看本课程
开通会员
该文章仅可免费阅读部分内容,如需阅读完整文章,请开通超级会员或单独购买本课程。
登录 后留言

精选留言(9)

  • 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
    2
    92
  • 杨逸林
    语音中有一个和文本内容不符合的地方,就是那个“正常的 0 字符”。语音是正常的空字符,文本就是前面引号的部分,是哪个对的呢,还是都对的?

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

    造成了困扰,不好意思啊!

    2020-10-25
    2
    8
  • 悟空聊架构
    文中最后的小结完美总结了本篇的主要内容。这篇可以先看小结内容,然后再通读全文,这样整体脉络会比较清晰。
    另外文中的一张总结图很棒,一图胜千言。
    2021-05-30
    3
  • 谢小路
    RESP 也可以通过抓包的方式来具体查看格式,使用 tcpdump 进行抓包得到的文件,使用 wireshark 进行查看,也比较直观。

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

    2020-11-19
    2
  • 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
  • Redis6 默认也是支持RESP2的
    2021-11-08
  • L-an
    老师,HSET testhash a 1 b 2 c 3 这个命令是不是有问题呢?
    长字符串类型返回长度之后应该有换行吧,应该是: $9\r\ntestvalue\r\n
    2021-08-24
  • 约书亚
    用旧的客户端连接6没看到返回合适有变化,2和3的兼容是服务端做的嘛?
    2021-02-05
  • dfuru
    *5\r\n:1\r\n:2\r\n,3.3\r\n:4\r\n$5\r\nhello\r\n
    2020-11-05
收起评论
9
返回
顶部