一、简单动态字符串(SDS)
参考资料:http://redisbook.com/preview/sds/different_between_sds_and_c_string.html
1.数据结构
类型 | 结构体 | 图 |
---|---|---|
动态字符串 | struct sdshdr { // buf 中已占用空间的长度 }; |
2.应用范围
Redis 的默认字符串,字符键值对中应
3.优点(VS C语言的字符串)
-
-
常数复杂度获取字符串长度。
-
杜绝缓冲区溢出。
-
减少修改字符串长度时所需的内存重分配次数。
-
二进制安全。
-
兼容部分 C 字符串函数。
-
二、链表
1.数据结构
类型 | 结构图 | 图 |
---|---|---|
双端链表节点 | /* // 前置节点 // 后置节点 // 节点的值(void*表示无类型的指针) } listNode; |
|
双端链表 | /* // 表头节点 // 表尾节点 // 节点值复制函数 // 节点值释放函数 // 节点值对比函数 // 链表所包含的节点数量 } list; |
2.应用范围
列表
三、字典
1.数据结构
类型 | 结构体 | 图 |
---|---|---|
哈希表 | /* // 哈希表数组 // 哈希表大小 // 该哈希表已有节点的数量 } dictht; | |
哈希表节点 | /* // 键 // 值 // 指向下个哈希表节点,形成链表 } dictEntry; | |
字典 | /* // 类型特定函数 // 私有数据 // 哈希表 // rehash 索引 // 目前正在运行的安全迭代器的数量 } dict; |
2. Rehash过程
负载因子
负载因子 = 哈希表已保存节点数量 / 哈希表大小(load_factor = ht[0].used / ht[0].size)
哈希表空间分配规则:
如果执行的是拓展操作,那么ht[1] 的大小为第一个大于等于ht[0] 的2的n次幂
如果执行的是收缩操作,那么ht[1] 的大小为第一个大于等于ht[0] 的2的n次幂
过程:
分配空间->数据转移->释放ht[0]
3.渐进式 rehash
渐进式rehash 的详细步骤:
1、为ht[1] 分配空间,让字典同时持有ht[0]和ht[1]两个哈希表
2、在几点钟维持一个索引计数器变量rehashidx,并将它的值设置为0,表示rehash 开始
3、在rehash 进行期间,每次对字典执行CRUD操作时,程序除了执行指定的操作以外,还会将ht[0]中的数据rehash 到ht[1]表中,并且将rehashidx加一
4、当ht[0]中所有数据转移到ht[1]中时,将rehashidx 设置成-1,表示rehash 结束
4.应用
Map
四、跳跃表
跳跃表原理:https://www.cnblogs.com/thrillerz/p/4505550.html
参考资料:http://redisbook.com/preview/skiplist/datastruct.html
1.数据结构
类型 | 结构体 | 图 |
---|---|---|
跳跃表节点 | /* // 成员对象 // 分值 // 后退指针 // 层 // 前进指针 // 跨度 } level[]; } zskiplistNode; | |
跳跃表 | /* // 表头节点和表尾节点 // 表中节点的数量 // 表中层数最大的节点的层数 } zskiplist; |
2.层高的确定
每个跳跃表节点的层高都是 1
至 32
之间的随机数
3.应用
有序集合
五、整数集合
1.数据结构
类型 | 结构体 | 图 |
---|---|---|
整数集合 | typedef struct intset { // 编码方式 // 集合包含的元素数量 // 保存元素的数组 } intset; |
2.升级
升级整数集合并添加新元素共分为三步进行:
1) 根据新元素的类型,扩展整数集合底层数组的空间大小,并为新元素分配空间
2) 将底层数组现有的所有元素都转换成新的编码格式,重新分配空间
3) 将新元素加入到底层数组中
3.应用
集合
六、压缩队列
1.数据结构
类型 | 结构体 | 图 | 说明 |
---|---|---|---|
压缩列表 |
| 1、zlbytes(4个字节):用于记录整个压缩列表占用的内存字节数 2、zltail(4个字节):记录要列表尾节点距离压缩列表的起始地址有多少字节 3、zllen(2个字节):记录了压缩列表包含的节点数量。 4、entryX:要说列表包含的各个节点 5、zlend(1个字节):用于标记压缩列表的末端 | |
ziplist 节点 | /* // prevrawlen :前置节点的长度 // len :当前节点值的长度 // 当前节点 header 的大小 // 当前节点值所使用的编码类型 // 指向当前节点的指针 } zlentry; |
2.应用
列表键和哈希键
七、Redis 对象
1.Redis 对象的结构
Redis 并没有直接使用这些数据结构来实现键值对数据库, 而是基于这些数据结构创建了一个对象系统,对象的结构如下:
对象结构体 | 对象类型 | 编码方式 |
---|---|---|
typedef struct redisObject { // 类型 //判断一个对象是否可以执行给定的命令 //不同的使用场景, 为对象设置多种不同的数据结构实现 } robj; | /* Object types */ // 对象类型 #define REDIS_STRING 0 #define REDIS_LIST 1 #define REDIS_SET 2 #define REDIS_ZSET 3 #define REDIS_HASH 4 | // 对象编码 #define REDIS_ENCODING_RAW 0 /* Raw representation */ #define REDIS_ENCODING_INT 1 /* Encoded as integer */ #define REDIS_ENCODING_HT 2 /* Encoded as hash table */ #define REDIS_ENCODING_ZIPMAP 3 /* Encoded as zipmap */ #define REDIS_ENCODING_LINKEDLIST 4 /* Encoded as regular linked list */ #define REDIS_ENCODING_ZIPLIST 5 /* Encoded as ziplist */ #define REDIS_ENCODING_INTSET 6 /* Encoded as intset */ #define REDIS_ENCODING_SKIPLIST 7 /* Encoded as skiplist */ #define REDIS_ENCODING_EMBSTR 8 /* Embedded sds string encoding */ |
2.类型和编码及对象直接的对应关系
通过 encoding
属性来设定对象所使用的编码, 而不是为特定类型的对象关联一种固定的编码, 极大地提升了 Redis 的灵活性和效率。
类型 | 编码 | 对象 |
---|---|---|
REDIS_STRING | REDIS_ENCODING_INT | 使用整数值实现的字符串对象。 |
REDIS_STRING | REDIS_ENCODING_EMBSTR | 使用 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_HT | 使用字典实现的哈希对象。 |
REDIS_SET | REDIS_ENCODING_INTSET | 使用整数集合实现的集合对象。 |
REDIS_SET | REDIS_ENCODING_HT | 使用字典实现的集合对象。 |
REDIS_ZSET | REDIS_ENCODING_ZIPLIST | 使用压缩列表实现的有序集合对象。 |
REDIS_ZSET | REDIS_ENCODING_SKIPLIST | 使用跳跃表和字典实现的有序集合对象。 |
3. Redis5种对象的结构(object.c)
对象类型 | 编码结构 | 场景 | |
---|---|---|---|
字符串对象 | int | 字符串对象可以保存为整数值, 并且这个整数值可以用 long 类型来表示 | |
raw | 保存的是一个字符串值, 并且这个字符串值的长度大于39 字节 | ||
embstr | 保存的是一个字符串值, 并且这个字符串值的长度小于等于 39 字节 | ||
列表对象 | ziplist |
| |
linkedlist | 不满足上面条件 | ||
哈希对象 | ziplist |
| |
hashtable | 不满足上面条件 | ||
集合对象 | intset |
| |
hashtable | 不满足上面条件 | ||
有序集合对象 | ziplist |
| |
skiplist | 不满足上面条件 |
八、Redis数据库的结构
redis数据库的k-v结构如下所示:
typedef struct redisDb { // 数据库键空间,保存着数据库中的所有键值对 // 键的过期时间,字典的键为键,字典的值为过期事件 UNIX 时间戳 // 正处于阻塞状态的键 // 可以解除阻塞的键 // 正在被 WATCH 命令监视的键 struct evictionPoolEntry *eviction_pool; /* Eviction pool of keys */ // 数据库号码 // 数据库的键的平均 TTL ,统计信息 } redisDb; |