参考 黄健宏.Redis 设计与实现[M].机械工业出版社:北京,2014
chapter 2 简单动态字符串
- SDS (简单动态字符串) 定义
struct sdshdr{
int len;
int free;
char buf[];
}
遵循C字符串以空字符结尾的管理
-
SDS 与C 字符串的区别
C字符串并不记录自身的长度信息
SDS 记录自身的长度 (len属性)
杜绝缓冲溢出
空间预分配
惰性空间释放 优化
二进制安全
(因为SDS使用len属性的值而不是空字符串来判断字符是否结束)
通过使用二进制安全的SDS ,而不是C字符串,使得red is 不仅可以保存文本数据,还可以保存任意格式的二进制数据 -
C SDS字符串区别
C | SDS |
---|---|
获取字符串长度的复杂度为O(N) | 获取字符串长度的复杂度为O(1) |
API 是不安全的,可能会造成缓冲区溢出 | API 是安全的,不会造成缓冲区溢出 |
修改字符串长度为N次必然需要执行N次内存重新分配 | 修改字符串长度为N次最多执行N次内存重新分配 |
只能保存文本文件 | 可以保存文本文件或者二进制数据 |
可以使用所有string.h库中的函数 | 可以使用一部分string.h库中的函数 |
chapter 3 链表
typedef struct listNode{
struct listNode *prev;
struct listNode *next;
void *value
}listNode
- 链表提供了高效的节点重排能力,以及顺序性的节点访问方式,并且可以通过增删节点来灵活的调整链表表的长度。
- 链表被广泛用于实现redis的各种功能,比如列表键,发布与订阅慢查询 监视器等
- 列表键的底层实现之一是链表
red is 的链表实现的特性 | |
---|---|
双端 | 链表节点带有prev和next指针,获取某个节点的前置节点和后置节点的复杂度都是O(1) |
无环 | 表头节点的prev指针和表尾节点的next指针都指向NULL,对链表的访问以NULL为终点 |
带表头指针和表尾指针 | 通过list结构的head指针和tail指针,程序获取链表的表头节点和表尾节点的复杂度为O(1) |
带链表长度计数器 | 程序使用list结构的len属性来对list持有的链表节点进行计数,程序获取链表中节点数量的复杂度为O(1) |
多态 | 链表节点使用void*指针来保存节点值,并且可以通过list结构的dup、free、match三个属性为节点值设置类型特定函数,所以链表可以用于保存各种不同类型的值 |
chapter4 字典
red is的字典视同哈希表为底层实现,一个哈希表可以有多个哈希表节点,而每个哈希表节点保存了字典中的一个键值对
- 哈希算法
当要将一个新的键值对添加到字典里面时,程序需要先根据键值对的键计算出哈希值和索引值,然后再根据索引值,
将包含新键值对的哈希表节点放到哈希表数组的指定索引上面。
哈希表使用链地址法来解决键冲突,被分配到同一个索引上的多个键值对会连接成一个单向链表。
chapter 5 跳跃表
跳跃表
skip list 是一种有序数据结构,他通过在每个节点中维持多个指向其他节点的指针,从而达到快递 访问节点的目的。
Redis使用跳跃表作为有序集合键的底层实现之一 (sorted set )
chapter6 整数集合
整数集合(intset) 是集合键的底层实现之一。
整数集合的底层为数组,这个数组以有序无重复的方式保存集合元素
chapter 7 压缩列表
ziplist 是列表键和哈希键的底层实现之一
chapter8 对象
Redis并没有直接使用这些数据结构来实现键值对数据库,而是基于这些数据结构创建了一个对象系统,这个系统包含字符串对象、列表对象、哈希对象、集合对象和有序集合对象这五种类型的对象,每种对象都用到了至少一种我们前面所介绍的数据结构
字符串对象的编码可以是int ,raw,embstr
列表对象的编码可是是ziplist ,linkedlist
ziplist编码的列表对象使用压缩列表作为底层实现,每个压缩列表节点(entry)保存了一个列表元素
另一方面,linkedlist编码的列表对象使用双端链表作为底层实现,每个双端链表节点(node)都保存了一个字符串对象,而每个字符串对象都保存了一个列表元素
哈希对象的编码可是是ziplist hashtable
ziplist编码的哈希对象使用压缩列表作为底层实现,每当有新的键值对要加入到哈希对象时,程序会先将保存了键的压缩列表节点推入到压缩列表表尾,然后再将保存了值的压缩列表节点推入到压缩列表表尾
另一方面,hashtable编码的哈希对象使用字典作为底层实现
集合对象的编码方式可以是intset,hashtable
有序集合的编码方式可以是ziplist skiplist
skiplist编码的有序集合对象使用zset结构作为底层实现,一个zset结构同时包含一个字典和一个跳跃表
- 内存回收
因为C语言并不具备自动内存回收功能,所以Redis在自己的对象系统中构建了一个引用计数(reference counting)技术实现的内存回收机制,通过这一机制,程序可以通过跟踪对象的引用计数信息,在适当的时候自动释放对象并进行内存回收。
chapter9
过期键删除策略
- 定时删除
- 惰性删除
- 定期删除
chapter 10 RDB持久化
命令
- SAVE 阻塞red is服务器进程
- BGSAVE 派生子进程
RDB持久化既可以手动执行也可以根据服务器的配置选项定期执行,该功能可以将某个时间点上的数据库状态保存到一个RDB文件中。
RDB 持久化功能所生成的RDB文件是一个经过压缩的二进制文件,通过该文件可以还原生成RDB文件时的数据库状态。
对于不同类型的键值对 RDB文件会使用不同的方式来保存他们
chapter 11 AOF 持久化
Append Only File
RDB持久化通过保存数据库中的键值对来记录数据库状态
通过保存redis服务器所执行的写命令来记录数据库状态
、
步骤
- append
- 文件写入
- 文件同步sync
chapter 16 Sentinel
Sentinel(哨岗、哨兵)是Redis的高可用性(high availability)解决方案:由一个或多个Sentinel实例(instance)组成的Sentinel系统(system)可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升级为新的主服务器,然后由新的主服务器代替已下线的主服务器继续处理命令请求