您的位置:首页 > 理论基础 > 数据结构算法

Redis底层数据结构总结

2015-08-12 10:05 567 查看
Redis用于存储的存储格式分为5种对象:String对象、List对象、HashTable对象、Set对象和SortedSet。

String字符串,用于保存字符串对象,同时可以作为缓冲区(AOF缓存区)

sdshdr{
int length;
int free;
char[] buffer;
}

C字符串和SDS之间区别

C字符串
SDS
获取字符串长度的复杂度为O(N)

O(1)
API不安全,可能造成缓冲区溢出
API安全,不会造成缓冲区溢出
修改字符串长度N次必然执行N次内存重新分配
最多执行N次内存重分配,大部分情况不需要
二进制不安全(之只能保存文本数据,中间不能包含空字符)
二进制安全,可以保存文本或者二进制数据
可以使用所有<string.h>库函数
使用部分库函数,字符串结尾同样以’\0’结尾,为了和C字符串部分兼容,可以使用部分库函数考虑
链表,用于链表键,慢查询、监视器、保存多个客户端状态,列表键包含较多元素或者包含的元素是较长的字符串时,会使用链表

双端
无环
带头指针和尾指针
带链表长度计数器
多态(*Void不同各类型的值)

字典,用于数据库与哈希键。Redis中的字典使用哈希表作为底层实现,Redis里的字典包含2个HashTable,H[0]用于日常用的hash,而H[1]则是重哈希的时候使用
哈希表使用链地址方法来解决键冲突的问题,被分配到同一个索引上的多个键会连接成一个单向链表
渐进式Hash

跳跃表SkipList
有序,每个节点维护多个执行其他节点的指针,从而达到快速访问节点的目的,平均O(logN),最坏O(N)复杂度查找,同时通过顺序性操作来批量处理节点
大部分情况可以和平衡树效率相当,然后跳跃表实现更加简单

SkipList

header
tail
level
length
同时,SkipList包含表头结点

SkipListNode{
//层
struct zskiplistLevel{
//前进指针
struct zskiplistNode * forward;
//跨度,用于记录里两个节点之间的距离
int span;
}level[];
//后退指针
struct zskiplistNode *backword;
//分值
//double score
//成员对象
robj *obj;
}zskiplistNode;

每个跳跃表节点的层高都是1-32之间的随机数
同一个跳跃表中,多个节点可以包含相同的分值,但是每一个节点的成员obj必须是唯一的
跳跃表的节点按照分值大小进行排序,当分值相同时,节点按照成员的大小进行排序

整数集合
当一个集合中只包含整数型元素,并且这个集合的元素数量不多时,Redis就会使用整数集合作为集合键的底层实现
有序的
struct intset{
//编码方式
uint32_t encoding;
//集合包含的元素
uint32_t length;
//保存元素的数组
int8_t contents[];
}

整数集合是集合键的底层实现之一
整数集合的底层实现为数组,这个数组以有序、无重复的方式保存着集合,在有需要时,程序会根据增加的元素的类型,改变这个数组的类型
编码的升级操作,给整数集合带来了操作上的灵活性,并且尽可能地节约内存空间
整数集合只支持升级操作,不支持降级

压缩列表(ZipList),用于当列表键只包含少量列表项,并且每个列表项要么是小整数值或者是长度较小的字符串

是一种为了节约内存空间而开发的特殊编码的顺序型数据结构(连续但不有序)
用于列表键或者哈希键的底层实现之一
可以包含多个节点,诶个节点可以保存一个字节数组或者整数型
新添加节点到列表件,或者从列表键中删除节点,可能会引发连锁更新的问题,但是这种操作出现的几率并不高

ZipList
zlbytes
(占用字节数)
zltail
记录表尾节点距离起始节点的offset
zllen
节点数
entry1
...
entryN
zlend
(末端标志)
ZipListNode
previous_entry_length
前驱节点的长度(1或者5字节)
encoding
content属性保存的类型信息
content
插入到指定节点之后,平均O(N),最坏O(N^2),最坏的情况是产生连锁更新,需要进行N次重分配操作,而每次空间从分配的最坏是O(N),故O(N^2).

对象,Redis中都是以对象的形式存在
RedisObject{
unsigned type:4 //五种redis对象
unsigned encoding:4//根据不同的编码,选择不同的底层实现
void *ptr;//指向底层实现的数据结构的指针
}

不同类型对应的编码对象

类型
编码
对象
Redis_String
Redis_Encoding_Int
整数型字符串
Redis_String
Redis_Encoding_Embstr
Redis_String
Redis_Encoding_Raw
Redis_List
Redis_Encoding_ZipList
Redis_List
Redis_Encoding_LinkedList
Redis_Hash
Redis_Encoding_Ziplist
Redis_Hash
Redis_Encoding_Hashtable
Redis_Set
Redis_Encoding_Intset
Redis_Set
Redis_Encoding_Hashtable
Redis_ZSet
1、Redis_Encoding_ZipList
2、Redis_Encoding_SkipList+字典实现
为啥要跳跃表+字段一起实现?效率考虑,跳越表范围查询特性保留
而字典:根据成员查找分值O(l)
通过encoding属性来设置对象所使用的编码,而不是为特定的类型关联一种固定的编码,极大提升了Redis的灵活性和效率,针对不同的场景做优化。

String对象
embstr:保存短字符串的一种优化编码方式,调用一次内存分配函数来连续分配redisObject和sdshdr,同时释放内存也只需要一次,同时能够利用字符串所有数据保存在同一块连续的内存里,更好地利用缓存。

Redis每一个键和值都是一个对象
Redis采用引用计数的方式实现内存垃圾回收,当一个对象不在使用时,对象就会被自动回收
Redis的共享值0-9999字符串
对象会记录自己最后一次被访问的时间,用于计算对象的空转时间
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: