【Redis】深入理解 Redis 常用数据类型源码及底层实现(2.版本区别+dictEntry & redisObject详解)
在【Redis】深入理解 Redis 常用数据类型源码及底层实现(1.结构与源码概述)一文中我们了解到Redis有如下8种底层数据结构:
- SDS动态字符串
- 双向链表
- 压缩列表 ziplist
- 哈希表 hashtable
- 跳表 skiplist
- 整数集合 intset
- 快速列表 quicklist
- 紧凑列表 listpack
关于这些底层数据结构是如何构成我们熟悉的Set、Sorted Set 、List、Hash……的Redis和7并不完全一致,我们来看看两个版本之间的区别
Redis 6.0.5
- String -> 动态字符串
- Set -> 哈希表+整数数组
- Sorted Set -> 跳表+压缩列表zipList
- List -> 双端链表+压缩列表zipList
- Hash -> 哈希表+压缩列表zipList

Redis 7 以后
2021.11.29以后,Redis 7 以后,没有ziplist了(ziplist被listpack取代)
- Hash -> 哈希表+紧凑列表listpack
- List -> quiecklist
- Sorted Set -> 跳表+紧凑列表listpack
- Set -> 哈希表+整数数组
- String -> 动态字符串

redisObject操作的底层定义位于server.h文件(Redis启动时就会加载server.),如下图

每个键值对都会有一个dictEntry
以set hello world为例,因为Redis是KV键值对的数据库,每个键值对都会有一个dictEntry,dictEntry表示哈希表节点的结构,指针*key(下图红
色框框部分)、指针*value(下图黄色框框部分),指针*next指向下一个dictEntry,dictEntry对象的声明在dict.c文件中,如下图:

其中*key指向String对象,*value既能指向String对象也能指向其他集合对象(如List、Set、ZSet、Hash),键值对的时间复杂度是O(1),值得注意的是,这里指向的都是Redis内部的抽象对象(redisObject)

redisObject结构的作用
Redis定义了redisObject结构体来表示string、hash、list、set、zset等数据类型,即Redis每个对象都是一个redisObject结构**
redisObject对象的声明位于server.h文件内,如下图:

struct redisObject {
unsigned type:4;
unsigned encoding:4;
unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or
* LFU data (least significant 8 bits frequency
* and most significant 16 bits access time). */
int refcount;
void *ptr;
};
为了便于操作,Redis采用了redisObject结构来统一5种不同的数据类型(下图绿色部分),这样所有的数据类型就可以以相同的形式在函数间传递而不用使用特定的类型结构。同时,为了识别不同的数据类型,redisObject中定义了type和encoding两个字段对不同的数据类型加以区别。
简单理解,redisObject就是string、hash、list、set、zset的父类,可以在函数间传递时隐藏具体的类型信息。
我们依次解释下redisObject中的各个参数:
-
type:对象的类型,4位(5种)OBJ_STRING、OBJ_LIST、OBJ_HASH、OBJ_SET、OBJ_ZSET- 使用
type xxx命令进行查看
-
encoding:当前值对象底层存储的编码类型,4位,即表示该类型的物理编码方式(同一种数据类型可能有不同的编码方式,比如String就提供了0、1、8这三种编码方式)- 使用
object encoding xxx命令进行查看
- 使用

-
lru:清除算法,lru表示当内存超限时采用LRU算法清除内存中的对象(24位,如果是LRU则记录对象最后一次被程序访问的时间(与内存回收相关)? -
refcount:引用计数,当refcount为0时,表示该对象已经不被任何对象引用(可以被当作垃圾回收了) -
*ptr:指向真正的底层数据结构的指针*ptr指向的底层数据结构有:SDS、双向链表、压缩列表、哈希表、跳表、整数集合等(指向下图中的黄色部分的箭头)

我们来举个例子,对于一条指令set age 17,当执行这条指令时,底层机会生成一个redisObject对象,这个对象中的type是String;encoding是int;lru记录的是最近被访问时间等(如下图)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!