Redis设计与实现-第一部分-对象

150 阅读4分钟

对象

Redis真正实现的是对象,是基于前面至少一种数据结构

一般会有键和值两个对象用redisObject表示

image.png

使用TYPE命令时返回的是键对应的值对象类型

使用OBJECT ENCODING命令返回键对应的值对象的编码

encoding属性极大提高了效率,不同场景下用不同编码

字符串对象

编码可以是int、raw(SDS)、embstr(SDS)

image.png 如果保存的字符串对象值长度小于等于44字节,会用embstr(针对短字符串有优化)

raw会调用两次内存分配来形成redisObject和sdshdr,释放需两次

embstr只需调用一次,释放也只需一次

long double类型也会用字符串来保存,执行操作才会转换成浮点型,然后把结果转换成字符串保存

编码转换

int类型的数据经过APPEND命令加入字符串,会转成raw

embstr是只读的,经过修改命令后会变更成raw编码

列表对象

可以是ziplist和linkedlist

image.png ////////////////////////////////////////// image.png 满足以下两个条件会用ziplist编码:

  • 所有字符串元素长度都小于64字节
  • 元素数量小于512个

哈希对象

可以是ziplist或者hashtable

image.png 满足一下条件会使用ziplist

  • 键和值的字符串长度都小于64字节

  • 键值对数量小于512

集合对象

intset或者hashtable

image.png 满足以下两个条件,会使用intset编码

  • 所有元素都是整数值

  • 元素数量不超过512个

有序集合对象

可以是ziplist或者skiplist skiplist编码的有序集合对象使用zset结构作为底层实现,一个zset结构同时包含一个字典和一个跳跃跳跃表

image.png 满足以下条件,会使用ziplist编码

  • 元素数量小于128个

  • 所有元素长度小于64字节

类型检查与命令多态

执行命令前,通过检查type属性来判断是否执行

然后检查encoding来确定具体用哪个对应的API来执行

内存回收

引用计数(跟jvm垃圾回收类似)

创建新对象时,引用计数值初始化为1

随着被程序引用和完成,计数增减,到0后对象内存会被释放

对象共享

和上面的内存回收搭配使用,

在初始化服务器时,会创建0-9999所有整数值的一万个字符串对象

当服务器需要这些字符串对象时,会直接引用,计数+1,而不会新建

由于验证复杂的对象耗cpu,所以redis只对整数值的字符串对象进行共享

对象空转时长

redisObject中有个lru属性记录了对象最后一次被访问的时间

由命令OBJECT IDLETIME命令返回,他会访问对象,但不会修改对象lru属性

如果内存超过maxmemory上限,会优先释放lru属性大的对象

总结

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

  2. Redis共有字符串、列表、哈希、集合、有序集合五种类型的对象,每种类型的对象至少都有两种或以上的编码方式,不同的编码可以在不同的使用场景上优化对象的使用效率

    字符串对象的编码可以是int(保存的整数值),raw(长字节),embstr(短字节)

    列表对象的编码可以是压缩列表(短字节),双端列表(长字节)

    哈希对象--->编码-->压缩列表,字典

    集合对象--->编码-->整数集合,字典

    有序集对象-->编码-->跳跃表, 压缩表

  3. 服务器在执行某些命令之前,会先检查给定键类型判断能否执行指定的命令,检查的是 "值对象"的类型

  4. Redis对象系统使用引用计数实现内存回收机制,引用计数还可以对象共享,初始时,服务器程序+键A==2个引用。

  5. Redis会共享值为0到9999的字符串对象。只对包含整数值的字符串对象进行共享

  6. 对象会记录自己的最后一次被访问的时间,这个时间用于计算对象的空转时间。服务器决定是否回收内存。