redis 数据类型和底层实现概况
Redis对外提供的数据类型
redis 提供的5种数据类型如下:
- string 类型
- list 类型
- set 类型
- hash类型
- zset 类型
Redis数据类型的底层数据结构
redis 底层提供的数据结构如下:
- dict 字典结构
- sds 简单动态字符串结构
- intset 整数集合结构
- linkedList 双端链表结构
- ziplist 压缩列表结构
- quicklist 快速列表结构
- skiplist 跳表结构
redis 底层数据结构和实现原理介绍
redis中 key 的存储
redisobject
// redisobject 至少占 16 byte , 再加上字符串的结尾标识符号 '\0',就是为什么embstr 存储不超过 44 字节
typedef struct redisObject {
unsigned type:4; // 占4 bits, 表示具体的数据类型
unsigned encoding:4; // 占 4 bits , 表示具体的编码方式
unsigned lru:LRU_BITS; // 占 24 bits,表示最近一次被访问的时间
int refcount ; // 占4 bytes , 表示对象被引用的计数值
void * ptr; // 占 8 bytes , 表示执行数据地址的指针
} robj;
redisDb
redis key 的存储过程
1、 计算key 的hash 值
2、 计算hash值在内存中的存储索引位置
[3、 解决hash 冲突]
4、对应字典dict(也叫hashtable)节点的下标,实质是dictEntry的下标
dict 结构详解
dict 字典结构介绍
dict 字典结构
sds 结构详解
redis 中的 string 类型底层的的3种编码形式
- OBJ_ENCODING_INT (int)
- OBJ_ENCODIG_EMBSTR (embstr)
- OBJ_ENCODING_RAW (raw)
场景一:以int 形式编码存储
当 value 值为 long 类型的整数,且长度小于 20 字节,以int 存储。
场景二:以 raw 形式编码存储
当value值为字符串,且长度大于 44 字节,以raw 存储。
场景三:以 embstr 形式编码存储
当value 值为字符串,且长度小于 44 字节,以embstr 存储。
注 : embstr 形式的编码,内存上是连续的,而raw形式的编码,内存是不连续的。
string 类型 的值,底层是采用 sds 存储。
sds ,简单动态字符串,是redis 封装的的一种数据结构。C 语言 字符串的空字符处理不足, redis 重新定义了一个表示字符串的数据结构 sds 。如下是 sds 的数据结构定义 :
3.x 版本的定义 :
struct sdshdr {
unsigned int len; // 记录buf[] 中已经使用的字节数
unsigned int free; // 记录buf[] 中为使用的字节数 , 思考是不是有点多月
char buf [];
}
6.x 版本的定义:
struct sdshrd8 {
uint8_t len; // 记录buf[] 已经使用的字节长度
uint_t alloc; // buf[] 分配的总长度
unsigned char flags; // 低3位保存数据类,高5位保留
char buf[];
} sdshdr8;
// 类的的 还有sdshdr16、sdshdr32、sdshdr64、sdshdr5
redis 底层采用 sds 存储的优势
1、 O(1) 时间复杂度获取字符串的长度
2、数据的存储是二进制安全的
3、sds 拥有自动扩充机制,杜绝缓冲区溢出现象
4、sds 拥有惰性空间释放机制,减少内存重新分配的次数。
intset 结构详解
linkedList 结构详解
linkedlist 数据结构
linkedlist 双端链表结构,由2个指针节点 listNode 和一个链表长度组成。
双端链接数据结构 (list数据结构)如下:
typedef struct list{
listNode *head ;
listNode *tail;
long len;
} list ;
linkedlist 中每个节点 listNode 的数据结构如下 :
typedef struct listNode {
struct listNode *prev; // 前驱节点
struct listNode *next; // 后继节点
void *value; // 节点内容
} listNode ;
双端链表数据结构的优点
1、双端,linkedlist是双端链表,在表头和表尾操作元素;
2、无环,linkedlist链表的表头prev指针指向null,表尾next指针指向null,没有构成环;
3、获取链表长度的算法时间复杂度是常数级,len属性记录链表长度,获取长度的时间负责读是 O(1) ;
4、带表头指针和表尾指针;
5、多态,可以存储数字类型,也可以存储字符串类型,也可以存储对象类型 ;
双端链表数据结构的缺点
1、linkedlist 在内存中开辟的内存空间不是连续的,不能通过内存空间的方式直接定位到元素,元素的获取耗性能;
2、因为在内存中开辟的内存空间不是连续的,数据量很大的时候会产生很多内存碎片,内存有效利用率不高;redis 是基于内存的数据结构,内存的有效利用率要求很高。linkedlist 数据结构和redis的内存有效利用要求之间是有矛盾的。所以redis底层并不是直接采用c实现的双端链表,而是采用ziplist(压缩链表)代替了linkedlist 。
ziplist 结构详解
ziplist
ziplist(压缩列表)是redis为节省内存而设计的。是由一系列特殊编码的连续空间数组块组成的顺序型的数据结构。一个ziplist可以包含任意多个节点(entry),每个节点可以保存一个字节数组或者多个整数值。
ziplist 数据结构
ziplist 数据结构
typedef struct ziplist {
} ziplist;
entry数据结构
typedef struct entry{
} entry ;
ziplist 数据结构的优点:
1、
2、
3、
ziplist 数据结构的缺点:
1、
2、
3、
4、redis 在 3.2版本开始引入了 quicklist 数据结构,联合ziplist 同时使用。