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之间区别
链表,用于链表键,慢查询、监视器、保存多个客户端状态,列表键包含较多元素或者包含的元素是较长的字符串时,会使用链表
双端
无环
带头指针和尾指针
带链表长度计数器
多态(*Void不同各类型的值)
字典,用于数据库与哈希键。Redis中的字典使用哈希表作为底层实现,Redis里的字典包含2个HashTable,H[0]用于日常用的hash,而H[1]则是重哈希的时候使用
哈希表使用链地址方法来解决键冲突的问题,被分配到同一个索引上的多个键会连接成一个单向链表
渐进式Hash
跳跃表SkipList
有序,每个节点维护多个执行其他节点的指针,从而达到快速访问节点的目的,平均O(logN),最坏O(N)复杂度查找,同时通过顺序性操作来批量处理节点
大部分情况可以和平衡树效率相当,然后跳跃表实现更加简单
SkipList
同时,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
ZipListNode
插入到指定节点之后,平均O(N),最坏O(N^2),最坏的情况是产生连锁更新,需要进行N次重分配操作,而每次空间从分配的最坏是O(N),故O(N^2).
对象,Redis中都是以对象的形式存在
RedisObject{
unsigned type:4 //五种redis对象
unsigned encoding:4//根据不同的编码,选择不同的底层实现
void *ptr;//指向底层实现的数据结构的指针
}
不同类型对应的编码对象
通过encoding属性来设置对象所使用的编码,而不是为特定的类型关联一种固定的编码,极大提升了Redis的灵活性和效率,针对不同的场景做优化。
String对象
embstr:保存短字符串的一种优化编码方式,调用一次内存分配函数来连续分配redisObject和sdshdr,同时释放内存也只需要一次,同时能够利用字符串所有数据保存在同一块连续的内存里,更好地利用缓存。
Redis每一个键和值都是一个对象
Redis采用引用计数的方式实现内存垃圾回收,当一个对象不在使用时,对象就会被自动回收
Redis的共享值0-9999字符串
对象会记录自己最后一次被访问的时间,用于计算对象的空转时间
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 |
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 (末端标志) |
previous_entry_length 前驱节点的长度(1或者5字节) | encoding content属性保存的类型信息 | content |
对象,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) |
String对象
embstr:保存短字符串的一种优化编码方式,调用一次内存分配函数来连续分配redisObject和sdshdr,同时释放内存也只需要一次,同时能够利用字符串所有数据保存在同一块连续的内存里,更好地利用缓存。
Redis每一个键和值都是一个对象
Redis采用引用计数的方式实现内存垃圾回收,当一个对象不在使用时,对象就会被自动回收
Redis的共享值0-9999字符串
对象会记录自己最后一次被访问的时间,用于计算对象的空转时间
相关文章推荐
- Manacher算法求回文半径
- 数据结构基础温故-7.排序
- 数据结构之---C语言实现最小生成树之prim(普里姆)算法
- AA树,2-3树二叉化
- 图算法之拓扑排序
- HDU-2647-邻接表模板
- 面试复习重点——数据结构、操作系统、计算机网络、数据库。
- 2015.08.10总结
- 【暑假】[实用数据结构]UVAlive 3026 Period
- 数据结构实验之链表七:单链表中重复元素的删除
- 数据结构实验之链表六:有序链表的建立
- 数据结构(Java语言)——LinkedList简单实现
- 数据结构实验之链表五:单链表的拆分
- 【暑假】[实用数据结构]UVAlive 3942 Remember the Word
- 2924: 营业额统计-伸展树-Splay-数据结构-模板详解
- 数据结构-线性表(学习笔记)
- 数据结构_堆排序介绍
- 数据结构实验:哈希表
- NOIP2009 提高组 最优贸易 解题报告
- 数据结构_线段树_例题_ I Hate It(HDU 1754)