可能就前面的记录一下,后面的很多是截图存在Typora上。。粘过来不显示,我也懒得弄了,应该是比较完整的笔记记录了,这里只放了一小部分,有了这些完全可以自己写一个小Redis玩具了,有空试试吧
简单动态字符串SDS
Redis没有直接使用C语言传统的字符串表示,而使自己构建了一种名为简单动态字符串的抽象SDS
C 字符串 | SDS |
获取字符串长度的复杂度为 O(N) 。 | 获取字符串长度的复杂度为 O(1) 。 |
API 是不安全的,可能会造成缓冲区溢出。 | API 是安全的,不会造成缓冲区溢出。 |
修改字符串长度 | 修改字符串长度 |
只能保存文本数据。 | 可以保存文本或者二进制数据。 |
可以使用所有 | |
Redis 的链表实现的特性可以总结如下:
- 双端: 链表节点带有
prev
next
指针, 获取某个节点的前置节点和后置节点的复杂度都是 O(1) 。 - 无环: 表头节点的
prev
next
NULL
NULL
为终点。 - 带表头指针和表尾指针: 通过
list
head
tail
指针, 程序获取链表的表头节点和表尾节点的复杂度为 O(1) 。 - 带链表长度计数器: 程序使用
list
len
list
持有的链表节点进行计数, 程序获取链表中节点数量的复杂度为 O(1) 。 - 多态: 链表节点使用
void*
list
dup
free
match
三个属性为节点值设置类型特定函数, 所以链表可以用于保存各种不同类型的值。
字典dict
rehash
一般字典都会有ht[0] ht[1]两个字典,而ht1就是rehash时用的
步骤:
- 判断是收缩还是扩容,确定ht1的size
- 将ht0的数据迁移到ht1
- 释放ht0,ht1成为ht0,新建ht1
当满足以下条件时,哈希表会进行扩展和收缩
- 服务器目前没有执行BGSIVE或者BGREWRITEAOF命令,并且哈希表的负载因子>=1
- 服务器目前正在执行这两条命令之一,且负载因子>=5
- 负载因子=ht[0].used / ht[0].size
- 负载因子小于0.1 进行收缩
原因:处于对执行BGSIVE或者BGREWRITEAOF命令时期时,redis会创建服务器进程的子进程,一般采用写时复制的策略优化子进程效率,所以子进程存在时会尽量避免rehash,因此提高了此时所需的负载因子
其次:rehash是渐进rehash
也就是说redis实际执行rehash时是采用每次对字典增删改查时顺便rehash,一些操作过后,字典rehash完成。当然了,在此期间,比如对字典的查找是在ht0和ht1上都进行查找
跳跃表
跳跃表是一种有序数据结构,支持Ologn的查找,最坏On。还可以通过顺序性操作批量处理节点
- header | tail 头尾指针
- level 跳跃表层数最大的节点(排除表头节点)
- 每层 记录了这一跳的前进指针以及跨度这两个属性,显然层数越多跳跃表的查找遍历就越快,跨度用来统计走过的距离,方便统计Rank
- 后退制作backward BW标记了向前一个结点的倒退指针,以实现表尾到表头的遍历操作
- 分值和对象,value从小到大构成跳跃表,对象保存一个SDS,value相同时按SDS字典序排
遍历时从高层往下查,碰到的前进指针跨度是1是往下走,知道碰到null证明到头了
整数集合
整数集合是集合间的底层实现之一,当set只有整数元素并且数量不多时,会采用整数集合
升级,但不支持降级
每当新添加的整数类型比现有类型长时,会进行升级操作,这样的动态策略可以节省内存
压缩列表
列表键和哈希键的底层实现之一
列表短且只有整数时使用压缩列表,zset的键值对数量小于128,长度都小于64字节时也使用这个
AOF
与rdb保存数据库键值对不同,AOF持久化通过保存Redis执行的写命令持久化
AOF持久化的实现
可以分为命令 追加append 文件写入 文件同步sync三个步骤
命令追加
比如SET KEY VALUE执行后,这条命令会最佳到服务器状态的aof_buf
缓冲区的末尾
AOF文件的写入与同步以及appendfsync选项
Redis 服务器进程就是一个时间循环,这个循环中的文件事件负责接收客户端的命令请求,以及向客户端发送命令回复,而时间事件负责执行serverCron函数这样需要定时运行的函数,
fsync和fdatasync同步函数
现代操作系统中用户调用write函数,通常先把数据放到内存缓冲区中,等到缓冲区满了或到了指定时间才会写入,这样虽然提高效率但也有停机时的不安全性,使用这两个同步函数强制操作系统将缓冲区的数据写入磁盘
appendfsync选项的值得效果
always时,最安全但也最慢,他最多只丢失一个事件循环中的命令数据
everysec时,每秒都有负责这个的子线程进行同步,够快且最多丢失一秒的追加命令
no时,同样每个事件循环都把缓冲区数据写到aof,但aof文件的同步由操作系统决定,因为一般不需要同步,所以这种模式的aof文件写入速度很快,但一旦发生丢失数据则会丢失上次同步aof后的所有数据
AOF重写
利用命令的合并和覆盖,创建一个新的aof文件替代原有的aof,新的aof只执行持久化必须的一部分的命令体积小很多
重写伪代码p150