redis源码解析(1):redisObject对象结构说明
简介
Redis 在实现键值对数据库时,并没有直接使用数据结构(简单动态字符串SDS,双端链表linkedlist,字典dict,压缩列表ziplist,整数集合intset,跳跃表skiplist等),而是基于已有的数据结构创建了一个对象系统,这个系统包含字符串对象、列表对象、哈希对象、集合对象和有序集合对象这五种类型的对象,每种对象都用到了至少一种数据结构.
当我们在 Redis 中创建一个键值对时,我们至少创建了两个对象,一个对象用作键值对的键
(键对象),另一个对象用作键值对的值(值对象)。键对象一定是 String 类型,而值对象可以是多种类型,比如 String,List,Set,Hash等多种对象类型。
redisObject对象数据结构说明
分析 redis3.0 版本
redisObject数据结构
typedef struct redisObject {
unsigned type:4; // redisObject表示对象类型,4个bits
unsigned encoding:4; // redisObject的编码类型
unsigned lru:REDIS_LRU_BITS; // redisObject的LRU时间
int refcount; // redisObject的引用计数
void *ptr; // 指向值的指针
} robj;
- type:redisObject 表示对象的类型,包括 String、List、Hash 等,它的底层数据结构是属性 encoding 表示(如下面的图1-1所示,redisObject 对象类型 REDIS_STRING 有 3 种数据结构 REDIS_ENCODING_RAW、REDIS_ENCODING_INT、REDIS_ENCODING_EMBSTR)。
- encoding:redisObject 的编码类型,是 Redis 内部实现各种数据类型所用的数据结构。
- lru:redisObject 的 LRU 时间。
- refcount:引用计数,实现内存回收机制。
- ptr:指向值的指针,指向底层数据结构,而数据结构由encoding属性决定
使用对象有什么好处?
1:根据对象的类型来判断一个对象是否可以执行给定的命令。
2:针对不同的数据场景,为对象设置多种不同的数据结构实现,从而优化在不同场景的使用效率。
3:对象系统还实现了基于应用计数的内存回收机制
4:Redis 的对象带有访问时间记录的信息,如果该键的空转时长较大那么会优先删除掉
type 、 encoding 和 ptr 是 redisObject 中最重要的三个属性
redisObject 、type、encoding 这 3 者关系图:
(图1-1)
redisObject中的type类型
type 记录了 redisObject 对象类型,它的值可能是以下常量中一个(位于 redis.h):
/* Object types 对象类型*/
#define REDIS_STRING 0 //字符串对象
#define REDIS_LIST 1 //列表对象
#define REDIS_SET 2 //集合对象
#define REDIS_ZSET 3 //有序集合对象
#define REDIS_HASH 4 //哈希表对象
redisObject中encoding编码
encoding 字段表示当前对象底层存储采用的数据结构,即对象的编码本质表示是对象底层采用了什么数据结构。
它的值可能是以下常量的其中一个(位于 redis.h):
// 对象编码,编码常量所对应的底层数据结构
#define REDIS_ENCODING_RAW 0 // Raw representation, 简单动态字符串
#define REDIS_ENCODING_INT 1 // Encoded as integer, long 类型的整数
#define REDIS_ENCODING_HT 2 // Encoded as hash table, 字典
#define REDIS_ENCODING_ZIPMAP 3 // Encoded as zipmap, 压缩map
#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, embstr编码的简单动态字符串
ptr 属性说明
ptr 是一个指针,指向实际保存值的数据结构,这个数据结构由 type 属性和 encoding 属性决定。
比如: 如果 redisObject 的 type 属性值为 REDIS_LIST , encoding 属性值为 REDIS_ENCODING_LINKEDLIST ,那么这个对象就是一个 Redis 列表LIST,它的值保存在一个双端链表内,而 ptr 指针就指向这个双端链表 LINKEDLIST;
lru 属性说明
这个属性记录了对象最后一次呗命令程序访问的时间,我们可以用这个属性来计算给定键多长时间没有被访问了。
另外作用:如果服务器设置打开了maxmemory选项,并且服务器回收内存算法为volatile-lru或者allkeys-lru,那么当服务器的内存超过了maxmemory设置的上限时,没有被访问的时间越长的键就越有限被服务器释放,从而回收内存
命令: object idletime 健名
redisObject、类型type、编码encoding 3者关系
redis 3.0 版本
redisObject 数据结构:
struct redisObject {
unsigned type:4; // redisObject表示对象类型
unsigned encoding:4; // redisObject的编码类型
void *ptr; // 指向值的指针
... ...
} robj;
根据上面小节的内容,redisObject 中 type 字段属性的取值可以有:
- REDIS_STRING
- REDIS_LIST
- REDIS_SET
- REDIS_ZSET
- REDIS_HASH
redisObject 中 encoding 字段属性的取值可以有:
- OBJ_ENCODING_RAW
- OBJ_ENCODING_INT
- OBJ_ENCODING_EMBSTR
- OBJ_ENCODING_HT
- OBJ_ENCODING_ZIPMAP
- OBJ_ENCODING_LINKEDLIST
- OBJ_ENCODING_ZIPLIST
- OBJ_ENCODING_INTSET
- OBJ_ENCODING_SKIPLIST
encoding编码对应的底层数据结构:
编码常量 | 编码对应的底层数据结构 |
---|---|
OBJ_ENCODING_RAW | 简单动态字符串SDS |
OBJ_ENCODING_INT | long类型的整型 |
OBJ_ENCODING_EMBSTR | embstr编码的简单动态字符串 |
OBJ_ENCODING_HT | 字典hashtable/dict |
OBJ_ENCODING_ZIPMAP | 压缩map |
OBJ_ENCODING_LINKEDLIST | 双端链表linkedlist |
OBJ_ENCODING_ZIPLIST | 压缩列表ziplist |
OBJ_ENCODING_INTSET | 整数集合intset |
OBJ_ENCODING_SKIPLIST | 跳跃表和字典 skiplist和dict |
字符编码中 raw 编码 和 embstr 编码的区别:
如果字符串对象保存都是一个字符串值,并且这个字符串值长度小于等于 32 字节,那么使用embstr 编码方式保存值,也就是说 embstr 是用来保存短字符串的值
这样做有什么好处呢?
-
1:raw 编码会调用2次内存分配函数分别创建 redisObject 结构和 sdshdr 结构, 而 embstr 编码则通过调用 1 次内存分配函数分配一块连续的空间,空间会包含 redisObject 和 sdshdr 结构。
-
2:那么释放的时候 raw 要释放 2 次, 而 embstr 只释放一次内存空间。