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 者关系图:

image
(图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 只释放一次内存空间。

参考

posted @ 2018-06-23 01:32  九卷  阅读(1064)  评论(0编辑  收藏  举报