Redis读书笔记(二)

Redis对象系统

Redis对象

  • 字符串(String)的底层实现方式
    • 直接保存整数值:字符串对象保存的是整数值,且可以用long类型来表示。
    • embstr编码的SDS:字符串对象保存的是一个长度小于等于39字节的字符串值。
    • SDS:字符串对象保存的是一个长度大于39字节的字符串值。
  • 列表(List)的底层实现方式
    • 压缩列表:列表对象保存的所有字符串元素的长度都小于64字节,且元素数量小于152个(注意:上限值是可以修改的,其他对象的上限值也是同洋的道理)。
    • 双端链表:不满足压缩列表的使用条件,则使用双端链表。
  • 哈希(Hash)的底层实现方式
    • 压缩列表:哈希对象保存的所有键值对的键和值的字符串长度都小于64字节,且键值对数量小于512个。
    • 字典:不满足压缩列表的使用条件,则使用字典。
  • 集合(Set)的底层实现方式
    • 整数集合:集合对象保存的所有元素都是整数,且元素数量不超过512个。
    • 字典:不满足整数集合的使用条件,则使用字典。
  • 有序集合(Zset)的底层实现方式
    • 压缩列表:有序集合保存的元素数量小于128个,且所有元素的长度都小于64字节。
    • 跳跃表+字典:不满足压缩列表的使用条件,则使用跳跃表+字典

Redis对象的实现

typedef struct redisObject {
  // 类型
  unsigned type:4;
  
  // 编码
  unsigned encoding:4;
  
  // 指向底层数据结构的指针
  void *ptr;
  
  // 引用计数
  int refcount;
  
  // 最后一次被命令程序访问的时间
  unsigned lru:8;
  
  //...
} robj;

对象的类型属性Type

类型常量 对象的名称
REDIS_STRING 字符串对象
REDIS_LIST 列表对象
REDIS_HASH 哈希对象
REDIS_SET 集合对象
REDIS_ZSET 有序集合对象

对象的编码属性Encoding和底层实现

类型 编码 对象
REDIS_STRING REDIS_ENCODING_INT 使用整数值实现的字符串对象
REDIS_STRING REDIS_ENCODING_EMBSTR 使用embstr编码的简单动态字符串实现的字符串对象
REDIS_STRING REDIS_ENCODING_RAW 使用Simple Dynamic String实现的字符串对象
REDIS_LIST REDIS_ENCODING_ZIPLIST 使用压缩列表实现的列表对象
REDIS_LIST REDIS_ENCODING_LINKEDLIST 使用双端链表实现的列表对象
REDIS_HASH REDIS_ENCODING_ZIPLIST 使用压缩列表实现的哈希对象
REDIS_HASH REDIS_ENCODING_HT 使用字典实现的哈希对象
REDIS_SET REDIS_ENCODING_INTSET 使用整数集合实现的集合对象
REDIS_SET REDIS_ENCODING_HT 使用字典实现的集合对象
REDIS_ZSET REDIS_ENCODING_ZIPLIST 使用压缩列表实现的有序集合对象
REDIS_ZSET REDIS_ENCODING_SKIPLIST 使用跳跃表和字典实现的有序集合对象

为什么需要同时使用跳跃表和字典来实现有序集合?

  1. 只使用字典来实现:执行查找的时间复杂度为O(1),但是执行范围性查询操作如ZRANGE、ZRANK等,需要对字典保存的所有元素排序,至少需要O(NlogN)的时间,以及额外的O(N)空间。
  2. 只使用跳跃表来实现:执行范围性查询的优点会被保留,但执行查找的时间复杂度为O(logN)。

所以为了查找和范围性查询都有尽可能快的执行,同时使用字典和跳跃表实现。

内存回收

对象的引用计数会随着对象的使用状态而不断变化:

  • 当创建一个新对象时,引用计数的值被初始化为1
  • 当对象被一个新程序使用时,引用计数的值会加1
  • 当对象不再被一个程序使用时,引用计数的值会减1
  • 当对象的引用计数变为0时,对象所占的内存会被释放

对象共享

Redis中让多个键共享同一个值对象(节约内存):

  • 将key的值指针指向一个现有的对象
  • 将被共享的值对象的引用计数加1

Redis只对包含整数值的字符串对象进行共享

当共享对象时,首先需要检查给定的共享对象和想创建的目标对象是否完全一致,只有在共享对象和目标对象完全相同的情况下才会使用共享对象。

  • 如果共享的是保存整数值的字符串对象,那么验证是否一致的时间复杂度为O(1)
  • 如果共享的是保存字符串的字符串对象,那么验证是否一致的时间复杂度为O(N)
  • 如果共享的是包含了多个值的对象,那么验证是否一致的时间复杂度为O(N*2)

所以考虑到CPU时间的限制,Redis只对包含整数的字符串对象进行共享。

posted @ 2022-07-07 16:01  ylyzty  阅读(21)  评论(0编辑  收藏  举报