《redis设计与实现》

写了第一版读书笔记,回头看一下,这本书写得足够精简,本身就是一个笔记,再做一次笔记感觉只是在做摘抄而已。决定换一种方式:只记录问题,如果忘记了问题怎么回答,那就回去看书
参考资料:https://redisbook.readthedocs.io/en/latest/internal/rdb.html#save-bgsave-aof-bgrewriteaof

思考总结:
redis 用C写的(指的是服务端,go-redis实际上也只是一个client而已,本质上也只是发一个网络请求。

第一部分 内部数据结构

解决的问题:

  1. 什么是SDS?redis为什么要用SDS?
  2. SDS扩容时的算法?分配策略会浪费内存吗?
  3. 思考:重启时(AOF/RDB)的内存分配?
  4. 什么是双端列表,代码结构?哪些模块用了双端列表?双端列表的迭代器怎样实现?
  5. 字典

两个主要用途是什么?(数据库部分可以看第五部分
Hash类型的键两种底层实现类型是什么?转换条件是什么(两个条件)?
dict为什么要用两个hash表实现?
redis的hash表又是如何实现的?(dictht)
添加新元素“dictadd”对应的三种情况详细流程是什么?
rehash的两个条件是什么?(dict_can_resize应该考虑进来)
什么叫自然rehash? 什么叫强制rehash?
rehash具体流程是什么?(三个步骤
什么是渐进式rehash?(两种方式具体是什么?
增删改查在两个hash-table上面的执行方式是什么?(原则:保证 ht[0] 的节点数量在整个 rehash 过程中都只减不增。
字典收缩(shrink)的具体过程? 收缩条件?收缩时的增删改查(基本和扩容保持一致

思考:hash键本质上就是用hash-table实现的,所谓字典dict本质上也是hash-table

《redis设计与实现》_第1张图片

  1. 跳表(跳跃链表)
    《redis设计与实现》_第2张图片

跳表具体实现方法是什么?
跳表的后退指针是什么? zrevrange等命令是怎么实现的?
跳表增删改查的时间复杂度都是多少?
跳表比红黑树优秀的地方在哪里?
跳表新的节点如何建索引?

第二部分:内存映射数据结构

前言:虽然内部数据结构非常强大, 但是创建一系列完整的数据结构本身也是一件相当耗费内存的工作, 当一个对象包含的元素数量并不多, 或者元素本身的体积并不大时, 使用代价高昂的内部数据结构并不是最好的办法。
为了解决这一问题, Redis 在条件允许的情况下, 会使用内存映射数据结构来代替内部数据结构。
内存映射数据结构是一系列经过特殊编码的字节序列, 创建它们所消耗的内存通常比作用类似的内部数据结构要少得多, 如果使用得当, 内存映射数据结构可以为用户节省大量的内存。
不过, 因为内存映射数据结构的编码和操作方式要比内部数据结构要复杂得多, 所以内存映射数据结构所占用的 CPU 时间会比作用类似的内部数据结构要多。

解决的问题:
1 整数集合

整数集合"intset"的实现方式是什么?数组里存的是指针还是具体的值? 其保存的元素的长度类型根据什么来决定?
数组有哪两个特性?
集合set 在什么情况下会用intset?
添加新元素到set中的升级具体过程?特别是重新分配内存后的移动顺序?

2 压缩列表
《redis设计与实现》_第3张图片
《redis设计与实现》_第4张图片

ziplist 是由一系列特殊编码的内存块构成的列表, 一个 ziplist 可以包含多个节点, 每个节点可以是什么类型?
上图每个域的作用是什么?zllen最大值为2^16?
节点的构成?pre_entry_length有哪两种情况?1个字节和5个字节是什么情况?encoding几种情况分别是什么?对应的length是什么?
ziplist的增加到尾部的方式? 删除和添加节点的最坏时间复杂度是多少?
ziplist如何遍历?

第三部分:Redis数据类型

为了解决不同类型的key实现方式,操作方式等各种兼容问题,Redis 构建了自己的类型系统, 这个系统的主要功能包括:redisObject 对象、基于 redisObject 对象的类型检查、基于 redisObject 对象的显式多态函数、对 redisObject 进行分配、共享和销毁的机制。

简单总结:任何一个key都用redisObject来表达。
《redis设计与实现》_第5张图片
《redis设计与实现》_第6张图片

redisObject 定义?
redisObject.type 有哪些值,意义是啥?
redisObject.encoding值和意义?
redisObject.ptr 指向什么?
什么叫 Flyweight 模式 ? 共享对象可以被哪些内部数据结构使用?
什么是引用计数? 为什么要记数?其具体机制是?

不同类型对象的操作

1 字符串 两种编码类型是什么 和 转换条件?
2 哈希表 的两种编码方式和 转换条件?
3 列表 的两种编码方式 和转换条件?
客户端的阻塞状态是如何维护的?如何脱离阻塞?
Push 维护的readyList 和 阻塞的blockingKeys 之间是如何工作的? ( readyList维护的结构看起来只是为了找到对应的key阻塞了哪些客户端。而遵守的原则也是先阻塞先服务
超时客户端如何自动接触阻塞?
4 集合的两种编码方式,切换条件
求交集、并集、差集的算法是什么? ( 差集有两种算法,用哪种取决于数量最小两个集合和所有集合的元素数量。
5 有序集合的两种编码,转换条件? (跳表和hash表使用的member和score实际上是同一个,即共享元素。

第四部分:功能的实现

事务

事务的三个阶段分别是?其命令执行的实现方式是?
事务状态和非事务状态下,客户端和服务端执行命令的区别主要是哪两个方面?
(WATCH 只能在客户端进入事务状态之前执行, 在事务状态下发送 WATCH 命令会引发一个错误, 但它不会造成整个事务失败, 也不会修改事务队列中已有的数据(和前面处理 MULTI 的情况一样)。

Watch指令是如何实现的?包括其状态如何维护?触发时机?具体如何实现事务失败?
事务的ACID
从一个情况分析一致性 ,“Redis 进程被终结” ?
事务为什么不是持久的?
假设事务一系列操作,中间某一个失败了,会影响整个事务吗? (只要入队时为报错则不会影响,因此事务也不保证原子性)

订阅与发布

《redis设计与实现》_第7张图片
《redis设计与实现》_第8张图片

用过吗?
订阅、发布、退订 以及 消息推送 的具体实现?
订阅模式的具体实现? ( PUBLISH 除了将 message 发送到所有订阅 channel 的客户端之外, 它还会将 channel 和 pubsub_patterns 中的模式进行对比, 如果 channel 和某个模式匹配的话, 那么也将 message 发送到订阅那个模式的客户端。

lua脚本

在我们的代码中,加锁直接用for循环+redis.setex
等到解锁的时候会,用lua脚本:redis.NewScript(if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) else return 0 end)

lua 环境的初始化中包含哪些重要的点?
这一部分没有看太懂。。。。。
慢查询日志的具体实现?redisServer的相关成员 含义。
当慢查询日志数量最大时,再添加会如何?

第五部分:数据库内部运作

解决的问题:

  • Redis 如何表示一个数据库? 数据库操作是如何实现的? (内部的字典增删改查)

这里需要补充:没有提及的内部hash算法:murmur

  • Redis key的过期机制是怎么实现的?四个过期指令的区别,以及底层实现的过期机制?是否过期的判断过程?
    expires字典里的 过期键什么时候会删除? 过期键惰性删除和定期删除的概念、优缺点、具体实现?

expires 字典的值只保存“以毫秒为单 位的过期 UNIX 时间戳” ,这就是说,通过进行转换,所有过期命令的效果最后都和 PEXPIREAT 命令的效果一样。

  • 过期键对持久化的影响:过期键会被保存在更新后的 RDB 文件、AOF 文件或者重写后的 AOF 文件里面吗? 附属节点会会如何处理过期键?处理的方式和主节点一样吗?
  • 数据库空间的收缩和扩容时机?(和字典的数据结构,扩容收缩时机也完全一样。
  • Redis 如何进行持久化?RDB 模式和 AOF 模式有什么区别?

rdb具体的执行逻辑?(替换
Save和BGSAVE有何区别? 请描述SAVE、BGSAVE、BGREWRITEAOF、AOF写入 的冲突竞争问题?
redis 重启时的载入如何实现?(除了订阅发布功能,其他命令一概返回错误
RDB文件结构是怎么样的?KEY-VALUE-PAIRS的结构是怎样的? VALUE的结构又是如何呢?

AOF的具体执行:WRITE 和 SAVE指的是什么?
命令同步到AOF的三个步骤是什么?(此处感觉有容易误解的地方, 首先命令传播 其实就是将执行的命令记录写入到AOF缓冲区,书里提到“AOF程序”容易让人误解aof是不是有一个单独的子线程?或者进程?
源代码里判断完是否写入aof后,会调用feedAppendOnlyFile, server.aof_buf =sdscatlen(server.aof_buf,buf,sdslen(buf)); 写入buf,都是在一个线程里做的。
AOF的三种保存模式分别介绍一下? 对性能和安全分别有什么影响?

redis如何读取AOF文件?
什么是AOF重写? (原理:根据键的类型, 使用适当的写入命令来重现键的当前值
AOF重写的后台执行

  • Redis 如何处理输入命令?它又是如何将输出返回给客户端的?
  • Redis 服务器如何初始化?传入服务器的命令又是以什么方法执行的?

你可能感兴趣的:(读书笔记)