Redis设计与实现---对象object

结构:

typedef struct redisObject{
    //类型  REDIS_STRING(字符串)、REDIS_LIST(列表)、REDIS_HASH(哈希)、REDIS_SET(集合)、REDIS_ZSET(有序集合)
    unsigned type:4;
    //编码  具体的底层数据结构类型
    unsigned encoding:4;
    //指向底层实现数据结构的指针
    void *ptr;
    //……
}robj;

一、字符串对象

type:

REDIS_STRING

encoding:

object编码常量
intREDIS_ENCODING_INT
embstrREDIS_ENCODING_EMBSTR
rawREDIS_ENCODING_RAW

 

 

 

 

 

使用场景:

整数值:int

字符串:

字符串长度<32字节时,使用embstr

字符串长度>=32字节时,使用raw

注:

1、int编码的字符串是只读的。执行任何修改命令都会转换为编码类型。

2、当值发生变化,当前的编码类型不能满足时,会发生转换。如:原来是整数类型,append了一条字符串,那么编码会从int转换为raw。

为什么字符串类型不只使用raw类型呢?

使用embstr的好处:

1、embstr编码的字符串对象所有数据都保存在一块连续的内存里面,所以比起raw类型能更好的利用缓存带来的优势。

2、分配内存、释放内存时,raw类型需要时两次,embstr类型只需一次。

结构图:

二、 列表对象

type:

REDIS_LIST

encoding:

object编码常量
ziplistREDIS_ENCODING_ZIPLIST
linkedlistREDIS_ENCODING_LINKEDLIST

 

 

 

 

使用场景:

以下两个条件 都满足 时使用ziplist:

1、列表对象保存的所有字符串元素的长度都小于64字节。

2、列表对象保存的元素数量小于512个。

其他情况使用linkedlist。

注:

上面两个条件的上限值是可以修改的。通过list-max-ziplist-value和list-max-ziplist-entries选项。

结构图:

三、哈希对象

type:

REDIS_HASH

encoding:

object编码常量
ziplistREDIS_ENCODING_ZIPLIST
hashtable

REDIS_ENCODING_HT

 

 

 

 

使用场景:

以下两个条件 都满足 时使用ziplist:

1、哈希对象保存的所有键值对的 键和值 的字符串长度都小于64字节。

2、哈希对象保存的键值对数量小于512个。

其他情况使用hashtable。

注:

上面两个条件的上限值是可以修改的。通过hash-max-ziplist-value和hash-max-ziplist-entries选项。

结构图:

 

四、集合对象

type:

REDIS_SET

encoding:

object编码常量
intsetREDIS_ENCODING_INTSET
hashtableREDIS_ENCODING_HT

 

 

 

 

使用场景:

以下两个条件 都满足 时使用intset:

1、集合对象保存的所有元素都是整数值。

2、集合对象保存的元素数量不超过512个。

其他情况使用hashtable。

注:

上面第二个条件的上限值是可以修改的。通过set-max-intset-entries选项。

结构图:

 

五、有序集合对象

type:

REDIS_ZSET

encoding:

object编码常量
ziplistREDIS_ENCODING_ZIPLIST
skiplistREDIS_ENCODING_SKIPLIST

 

 

 

 

使用场景:

以下两个条件 都满足 时使用ziplist:

1、有序集合保存的元素数量小于128个。

2、有序集合保存的所有元素成员的长度都小于64字节。

其他情况使用skiplist。

注:

1、上面两个条件的上限值是可以修改的。通过zset-max-ziplist-entries和zset-max-ziplist-value选项。

2、使用skiplist时,实际上是同时使用了跳跃表和字典来实现的。

原因:

只使用字典,zrank、zrange等命令需要对所有元素排序,时间复杂度至少O(logN)、额外空间O(N)。

只使用跳跃表,zscore命令时间复杂从O(1)上升为O(logN)。

所以范围性操作使用跳跃表,点操作使用字典。

 

结构图:

注:字典和跳跃表会共享元素的成员和分值,所以不会造成任何数据重复,也不会浪费任何内存。

六、类型检查和命令多态

命令分类:

1、对任何类型的键执行,如:DEL、EXPIRE、RENAME、TYPE、OBJECT等命令。

2、对特定类型的键执行,如:SET、GET、APPEND等只能对字符串键执行。

类型检查:

在执行一个类型特定的命令之前,Redis会先检查输入键的类型(即type属性的值)是否正确,然后再决定是否执行。

过程图:

命令多态:

列表值对象是ziplist或者linkedlist编码,LLEN命令都可以正常执行。

DEL、EXPIRE是基于类型(type)的多态,LLEN是基于编码(encoding)的多态。

过程图:

七、内存回收

typedef struct redisObject{
    //类型  REDIS_STRING(字符串)、REDIS_LIST(列表)、REDIS_HASH(哈希)、REDIS_SET(集合)、REDIS_ZSET(有序集合)
    unsigned type:4;
    //编码  具体的底层数据结构类型
    unsigned encoding:4;
    //指向底层实现数据结构的指针
    void *ptr;
    //引用计数
    int refcount;
    //……
}robj;

创建一个新对象,refcount=1;

该对象被一个新程序使用时,refcount+1;

该对象不再被一个程序使用时,refcount-1;

该对象refcount=0时,该对象所占内存释放。

API:

函数作用
incrRefcount将对象的引用计数值增一。
decrRefcount将对象的引用计数值值减一,当对象的引用计数值等于0时,释放对象。
resetRefcount将对象的引用计数值设置为0,但并不释放对象,这个函数通常在需要重新设置对象的引用计数值时使用。

 

 

 

 

 

 

八、对象共享

refcount属性还带有对象共享的作用。

目的:节约内存

对象共享的对象只有  整数值 。

共享结构如图: 

Redis会在初始化服务器时,创建一万个字符串对象(0~9999),当用到值为0~9999的字符串对象时,服务器就会使用这些共享对象。

注:创建共享字符串对象的数量可以通过redis.h/REDIS_SHARED_INTEGERS常量修改。

为什么Redis不共享包含字符串的对象?

验证操作:共享对象和目标对象完全相同。

1)共享对象为保存整数值的字符串对象,验证操作复杂度为O(1);

2)共享对象为保存字符串值的字符串对象,验证操作复杂度为O(N);

3)共享对象为包含了多个值(或者对象的)对象(如列表对象、哈希对象),验证操作复杂度为O(N^2);

所以尽管能节约内存,但受到CPU时间的限制。

九、空转时长

typedef struct redisObject{
    //类型  REDIS_STRING(字符串)、REDIS_LIST(列表)、REDIS_HASH(哈希)、REDIS_SET(集合)、REDIS_ZSET(有序集合)
    unsigned type:4;
    //编码  具体的底层数据结构类型
    unsigned encoding:4;
    //指向底层实现数据结构的指针
    void *ptr;
    //引用计数
    int refcount;
    //最后一次被命令程序访问的时间
    unsigned lru:22;
}robj;

操作命令:

object idletime <key>

计算规则:

空转时长=当前时间-lru时间

注:

object idletime命令的实现是特殊的,在访问键的值对象时,不会修改值对象的lru属性。

 

总结

stringint、embstr、raw
listziplist、linkedlist
hashtableziplist、ht
set

                                      intset、ht

zsetziplist、skiplist

 

重点回顾

Redis数据库中的每个键值对的键和值都是一个对象。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值