redis源码阅读
redis的源码非常简洁,只有两万多行,却实现了一个完整的系统。于是通过结合黄健宏老师的《Redis设计与实现》和源代码,对Redis 3.0的源码进行了学习。阅读Redis的源码作为本学期的目标之一,现在做一个小的总结。
首先是数据结构与对象:
redis 3.0 基本数据类型:1.String(字符串) 2.List(列表) 3.Hash(字典) 4.Set(集合) 5.Sorted Set(有序集合)
第一部分 Redis的内部数据结构:
1.简单动态字符串
通过空间预分配(新长度小于最大预分配1M,将预分配同等大小使得len=free的值,否则预分配1M的大小空间)和惰性空间释放(不立即释放空间,使用free进行记录)优化策略减少字符串修改带来的重分配次数。SDS依然遵循C字符串以空字符结尾的惯例,可以重用<string.h>中的代码。
2.链表
链表由list结构和listNode(有前向指针和后向指针,使用指针保证可以保存不同值)结构组成,可以直接指向表头或者表尾,保存了结点的数量。
3.跳跃表
跳跃表是一种有序数据结构,由zskiplist和zskiplistNode两个结构组成,level是结点的层,根据幂次定律(越大的数出现的概率越小)随机生成一个介于1~33之间的值,level中有前进指针和跨度信息,跨度信息可以用来计算排位rank。
4.整数集合
整数集合主要由intset结构和保存元素的数组组成,元素的位数由encoding的值决定。contents中的元素时有序的。整数集通过升级的方式提高整数集合的灵活性,尽可能的节约内存。整数集合不支持降级。
5.压缩列表
是一系列连续内存快组成的顺序数据结构。可以包含任意多个结点,程序通过指针运算根据当前结点的起始地址来计算前一个结点的起始地址,即压缩列表从表尾向表头进行遍历。添加结点或删除结点都可能引起连锁反应,在实际中发生的可能性不是很大。
*字典
字典中包含两个哈希表,ht[1]只在rehash时使用。哈希表中使用链表来解决冲突。rehash时ht[1]的大小为第一个大于等于ht[0].used*2的,如果进行收缩操作,ht[1]的大小为ht[0].used的
。扩展收缩的条件:
1)没有执行BGSAVE或者BGREWRITEAOF时,负载因子大于等于1。
2)在在执行前面两个命令时,负载因子大于等于5。
3)负载因子小于0.1进行收缩。
rehash是渐进式进行的,rehashidx来记录rehash的索引。
第二部分 Redis中的对象系统:
Redis基于实现的数据结构建立了一个对象系统,Redis根据不同的场景,动态为Redis对象设置不同的底层实现,提高了内存的利用率。
对象 | 底层编码 | 条件 |
STRING | INTSET(整数集合) | value可以用long类型保存的整数 |
STRING | EMBSTR(embstr编码动态字符串) | value是字符串,长度小于等于39字节 |
STRING | RAW(简单动态字符串) | value是字符串,长度大于39字节 |
LIST | ZIPLIST(压缩列表) | 元素长度都小于64字节,个数小于512个 |
LIST | LINKEDLIST(双端链表) | 不满足上述条件 |
HASH | ZIPLIST(压缩列表) | 所有键和值的字符串长度小于64字节,键值对数量小于512 |
HASH | HT(字典) | 不满足上述条件 |
SET | INTSET(整数集合) | 所有元素都是整数值,元素数量不超过512个 |
SET | HT(字典) | 不满足上述条件 |
ZSET | ZIPLIST(压缩列表) | 保存元素数量小于128个,所有成员小于64字节 |
ZSET | SKIPLIST(跳跃表和字典) | 不满足上述条件 |
上面的条件可以在config配置文件中进行更改。
第三部分 Redis数据库实现
1. Redis.h中RedisDb(默认为16个)的结构
2. 过期键的删除策略
Redis使用惰性删除策略和定期删除策略两种策略。配合两种策略可以在合理使用cpu时间与避免内存浪费之间取得平衡。
3. RDB持久化与AOF持久化
RDB是保存的Redis快照,AOF是保存的执行的命令。
第四部分 客户端与服务端运行
1. Redis事件驱动
2. 服务端
在redis.c中的main()函数中,首先是initServerConfig()进行Redis服务器的状态初始化,接着是initServer()进行服务器数据结构初始化。
3. 客户端
将输入的命令转化为协议,并发送给服务端。初始化时根据条件创建执行Lua脚本包含redis命令的伪客户端,创建执行AOF文件伪客户端。每个客户端的状态保持在redisServer的*clients链表中。
第四部分 分布式集群数据库
暂时跳过
第五部分 功能部分
发布订阅
事务
Lua脚本
排序
二进制位数组